2015-11-25 #pragma预处理分析听课笔记

1、#pragma是编译器指示字,用于指示编译器完成一些特定的动作。

2、#pragma定义的很多指示字都是编译器和系统特有的。

3、#pragma在不同的编译器之间是不可移植的。

    3.1  预处理器将忽略它所不认识的#pragma指令

    3.2两个不同的编译器可能会以两种不同的方式解释同一条#pragma指令,这是由编译器厂商决定的。

4、一般用法: #pragma   parameter  //不同的parameter参数语法和意义各不相同。

 

    4.1   #pragma  message

       4.1.1  message参数在大多数的编译器中都有相似的实现。//注意:message参数是VC编译器特有的,GCC是没有的。

       4.1.2  message参数在编译时输出消息到编译输出窗口中。

       4.1.3  message参数可以用于版本控制。

       4.1.4 使用实例:

    

 1 #include <stdio.h>
 2 
 3 #define ANDROID20
 4 
 5 #if defined(ANDROID20)
 6     #pragma message("Compile Android SDK 2.0...")
 7     #define VERSION "Android 2.0"
 8 #elif defined(ANDROID23)
 9     #pragma message("Compile Android SDK 2.3...")
10     #define VERSION "Android 2.3"
11 #elif defined(ANDROID40)
12     #pragma message("Compile Android SDK 4.0...")
13     #define VERSION "Android 4.0"
14 #else
15     #error Compile Version is not provided!
16 #endif
17 
18 int main()
19 {
20     printf("%s\n", VERSION);
21 
22     return 0;
23 }

在VC的环境下,编译时在输出窗口将显示我们设定的版本信息。

   4.2 #pragma  pack

   4.2.1  关于内存对齐

  不同类型的数据在内存中按照一定的规则排列,而不是顺序的一个接一个的排放,这就是内存对齐。

 struct  T1

{

char c1;

short s1;

char c2;

int i1;

};

struct  T2

{

char c1;

char c2;

short s1;

int i1;

两者所占的空间大小一样吗?我们在VS下写了一个测试代码如下:

 1 #include<stdio.h>
 2 
 3 struct  T1
 4 
 5 {
 6 
 7 char c1;
 8 
 9 short s1;
10 
11 char c2;
12 
13 int i1;
14 
15 };
16 
17 
18 struct  T2
19 
20 {
21 
22 char c1;
23 
24 char c2;
25 
26 short s1;
27 
28 int i1;
29 
30 };
31 
32 
33 void main()
34 {
35 printf("%d,%d",sizeof(struct T1),sizeof(struct T2));
36 getchar();
37 }

测试结果为:12,8

    4.2.2  为什么要内存对齐?

    a,CPU读取内存时不是连续读取的而是分块读取的,而块的大小只能是1,2,4,8,16字节。

    b,当读取操作的数据未对齐的时候,则需要两次总线周期来访问内存,因此性能会大打折扣。

        eg:

          struct  T

          {

           char c;

          short s;

          }

   假如不进行内存对齐的话,则需要先读出c,然后读s,假如进行了4字节内存对齐的话,则可以一次性的将c和s读取出来,这样将大大节省读写时间。

    c,某些硬件平台只能从规定的地址处取某些特定类型的数据,否则将抛出硬件异常。例如某些硬件只能进行偶地址访问。

   

 

      4.2.3#pragma  pack能够改变编译器默认的对齐方式。

      实例程序如下:

     

 1 #include <stdio.h>
 2 
 3 #pragma pack(4)
 4 
 5 struct S1
 6 {
 7     short a;
 8     long b;
 9 };
10 #pragma pack()
11 
12 
13 #pragma pack(8)
14 struct S2
15 {
16     char c;
17     struct S1 d;
18     double e;
19 };
20 
21 #pragma pack()
22 
23 int main()
24 {
25     struct S2 s2;
26     
27     printf("%d\n", sizeof(struct S1));
28     printf("%d\n", sizeof(struct S2));
29     printf("%d\n", (int)&(s2.d) - (int)&(s2.c));
30     getchar();
31 
32     return 0;
33 }

运行结果是8,24,4
第三行用于告诉编译器以下内容,进行4字节对齐,

第十三行用于告诉编译器以下内容,进行8字节对齐。编译器默认的对齐方式一般是4字节对齐方式。

具体结果为什么是这样,我们先不说。

   4.2.4 关于struct所占用的内存大小的计算:

  个人总结的几点:

  1、结构体的第一个成员的地址偏移量(offset)为0;

  2、在没有用#pragma pack(n)指令指定对齐参数n时,对齐参数n=结构体中占用内存最大的那个成员变量所占内存的大小m;在用#pragma pack(n)指令指定对齐参数n后,系统将min(n,m)作为对齐参数。

 3、每个成员变量都要对齐,如果对齐参数为n,该成员变量所占字节数为p,则该成员变量的偏移地址%min(n,p)=0。也就是最小化长度规则。

 4、结构体总大小: 对齐后的长度必须是对齐参数n的整数倍。

 5、补充:如果结构体A中还有结构体B,那么B的对齐方式是选它里面最长的成员的对齐方式
所以计算结构体大小要走三步,首先确定是当前程序按照几对齐,接着计算每个结构体变量的大小和偏移,最后计算结构体总大小。

 

 

   

posted @ 2015-11-26 14:25  玩呀熊熊  阅读(147)  评论(0编辑  收藏  举报