c特性 __attribute__

このドキュメントは、C 言語での __attribute__ の使用_[qljun] qlexcel のブログ - CSDN ブログ___attribute__ から入手しました。

個人的な学習/復習用

1. はじめに

GNU C の主な機能は __attribute__ メカニズムです。__attribute__ では関数属性(Function Attribute)、変数属性(Variable Attribute)、型属性(Type Attribute)を設定できます。

属性の書き込みの特徴は、__attribute__ の前後に 2 つのアンダースコアがあり、その後に元の 1 組のかっこが続き、対応する __attribute__ パラメーターがかっこ内にあることです。

属性の構文形式は次のとおりです: __attribute__ ((attribute-list))

キーワード __attribute__ は、構造体 (struct) または共用体 (union) に属性を設定することもできます。およそ 6 つのパラメータ値、つまり、aligned、packed、transparent_union、unused、deprecated、may_alias を設定できます。

__attribute__ パラメーターを使用する場合、パラメーターの前後に「__」 (2 つのアンダースコア) を追加することもできます。たとえば、aligned の代わりに __aligned__ を使用すると、対応するヘッダー ファイルで Don't Care if の代わりに使用できます。ヘッダー ファイルに同じ名前のマクロ定義があります。

2. __attribute__ のパラメータ導入

1、整列

次のように、オブジェクトのアライメント形式をバイト単位で指定します。

struct S {
 
short b[3];
 
} __attribute__ ((aligned (8)));
 
 
typedef int int32_t __attribute__ ((aligned (8)));

この宣言により、コンパイラは、struct S または int32_t 型の変数が 8 バイト アラインメントで割り当てられることを (可能な限り) 保証するようになります。

前述したように、配置形式を手動で指定することも、同様にデフォルトの配置を使用することもできます。aligned の直後に指定された数値が続かない場合、コンパイラはターゲット マシンにとって最大かつ最も有益なアライメントを使用します。例えば:

struct S {
 
short b[3];
 
} __attribute__ ((aligned));

ここで、sizeof (short) のサイズが 2byte の場合、S のサイズは 6 になります。値が 6 以上になるように 2 の累乗値を取得すると、値は 8 になるため、コンパイラは S 型のアラインメントを 8 バイトに設定します。

aligned 属性を使用すると、設定されているオブジェクトがより多くのスペースを占めるようになりますが、逆に、packed を使用すると、オブジェクトが占めるスペースを減らすことができます。

属性属性の有効性はコネクタにも関係していることに注意してください。コネクタが最大 16 バイトのアライメントしかサポートしていない場合、現時点で 32 バイトのアライメントを定義することは役に立ちません。

2、梱包済み

この属性を使用して、構造体または共用体の型を定義し、その型の各変数のメモリ制約を設定します。これは、コンパイル中に構造体の最適化されたアライメント (1 バイト アライメントを使用) をキャンセルし、実際に占有されているバイト数に従ってアライメントするようにコンパイラに指示するためのものであり、これは GCC の独自の構文です。この関数はオペレーティング システムとは何の関係もありません。コンパイラと関係があります。gcc コンパイラはコンパクト モードではありません。私は Windows を使用していますが、vc コンパイラはコンパクトではありませんが、tc コンパイラはコンパクトです。

次の例では、packed_struct 型の変数配列内の値は近くなりますが、内部メンバー変数 s は「パック」されません。内部メンバー変数をパックしたい場合は、unpacked-struct も実行されます。対応する制約にはパックを使用する必要があります

struct unpacked_struct
{
      char c;
      int i;
};
         
struct packed_struct
{
     char c;
     int  i;
     struct unpacked_struct s;
}__attribute__ ((__packed__));

のように:

在TC下:struct my{ char ch; int a;}      sizeof(int)=2;sizeof(my)=3;(紧凑模式)
 
在GCC下:struct my{ char ch; int a;}     sizeof(int)=4;sizeof(my)=8;(非紧凑模式)
 
在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed))        sizeof(int)=4;sizeof(my)=5

次の例では、__attribute__ 属性を使用していくつかの構造体とその変数を定義し、結果の出力と分析を示します。コードは次のとおりです。

struct p
{
    int a;
    char b;
    short c;
 
}__attribute__((aligned(4))) pp;
 
struct m
{
    char a;
    int b;
    short c;
}__attribute__((aligned(4))) mm;
 
struct o
{
    int a;
    char b;
    short c;
}oo;
 
struct x
{
    int a;
    char b;
    struct p px;
    short c;
}__attribute__((aligned(8))) xx;
 
int main()
{           
    printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",sizeof(int)
                                                ,sizeof(short),sizeof(char));
    printf("pp=%d,mm=%d \n", sizeof(pp),sizeof(mm));
    printf("oo=%d,xx=%d \n", sizeof(oo),sizeof(xx));
    return 0;
}

出力結果:

sizeof(int)=4,sizeof(short)=2.sizeof(char)=1
pp=8,mm=12
oo=8,xx=24

分析: これはバイト アラインメントの原理です。ここにアクセスできます: バイト アラインメント

3、で

絶対位置指定では、変数や関数をフラッシュ内で絶対的に配置したり、RAM 内で配置したりできます。

1) フラッシュ内に配置します。これは、工場出荷時に設定されたパラメータ、ホストコンピュータによって設定されたパラメータ、ID カードの ID 番号、フラッシュマークなどの情報を硬化するために一般的に使用されます。

2) 定義された長さはスタックまたはフラッシュのサイズを超えることはできません。超えない場合、スタックおよびフラッシュはオーバーフローします。

4、セクション

セクションに関して言えば、RO RI ZI と言う必要があります。ARM コンパイラのコンパイル後、コードはさまざまなセクションに分割されます。RO セクション (ReadOnly) にはコード セクションと定数が格納され、RW セクション (ReadWrite) には読み取りおよび書き込み可能な静的コードが格納されます。変数とグローバル変数の ZI セクション (ZeroInit) は、0 に初期化された RW セグメントに格納される変数です。

したがって、この記事の一般的な意味は明らかです。 __attribute__((section("section_name"))) の機能は、指定された名前 "section_name" に対応するセクションに関数または関数のデータを配置することです。

1) コンパイル時に変数のセグメントを指定します。

__attribute__((section("name")))
RealView Compilation Tools for µVision Compiler Reference Guide Version 4.0 
 
Home > Compiler-specific Features > Variable attributes > __attribute__((section("name"))) 
 
4.5.6. __attribute__((section("name")))
Normally, the ARM compiler places the objects it generates in sections like data and bss. However, you might require additional data sections or you might want a variable to appear in a special section, for example, to map to special hardware. The section attribute specifies that a variable must be placed in a particular data section. If you use the section attribute, read-only variables are placed in RO data sections, read-write variables are placed in RW data sections unless you use the zero_init attribute. In this case, the variable is placed in a ZI section.
 
Note
This variable attribute is a GNU compiler extension supported by the ARM compiler.
 
Example
/* in RO section */
const int descriptor[3] __attribute__ ((section ("descr"))) = { 1,2,3 };
/* in RW section */
long long rw[10] __attribute__ ((section ("RW")));
/* in ZI section *
long long altstack[10] __attribute__ ((section ("STACK"), zero_init));/

2) コンパイル時に関数のセグメントを指定します。

__attribute__((section("name")))
RealView Compilation Tools for µVision Compiler Reference Guide Version 4.0 
 
Home > Compiler-specific Features > Function attributes > __attribute__((section("name"))) 
 
4.3.13. __attribute__((section("name")))
The section function attribute enables you to place code in different sections of the image.
 
Note
This function attribute is a GNU compiler extension that is supported by the ARM compiler.
 
Example
In the following example, Function_Attributes_section_0 is placed into the RO section new_section rather than .text.
 
void Function_Attributes_section_0 (void) __attribute__ ((section ("new_section")));
void Function_Attributes_section_0 (void)
{
    static int aStatic =0;
    aStatic++;
}
In the following example, section function attribute overrides the #pragma arm section setting.
 
#pragma arm section code="foo"
  int f2()
  {
      return 1;
  }                                  // into the 'foo' area
 
  __attribute__ ((section ("bar"))) int f3()
  {
      return 1;
  }                                  // into the 'bar' area
 
  int f4()
  {
      return 1;
  }                                  // into the 'foo' area
#pragma arm section

5、別名

エイリアス:

#define module_init(initfn)                                        \
        static inline initcall_t __inittest(void)                \
        { return initfn; }                                        \
        int init_module(void) __attribute__((alias(#initfn)));

__inittest は定義された関数が initcall_t 型に準拠しているかどうかを検出するだけであり、__inittest 型に準拠していない場合はコンパイル時にエラーが報告されます。したがって、実際のマクロ定義は次のようになります。

#define module_init(initfn)                                 \
        int init_module(void) __attribute__((alias(#initfn)));

したがって、動的ロード方式を使用する場合、 module_init および module_exit マクロを使用せずに、 init_module および cleanup_module 関数を直接定義でき、効果は同じです。

alias 属性は gcc の一意の属性で、init_module を関数 initfn のエイリアスとして定義します。したがって、 module_init(hello_init) の機能は、アドレスが hello_init と同じである変数名 init_module を定義することです。

6. 複数の属性、併用

u8 FileAddr[100] attribute ((section ("FILE_RAM"), zero_init,aligned(4)));    

おすすめ

転載: blog.csdn.net/qq_58550520/article/details/129147984