C语言进阶:24、#pragma使用分析

#pragma用于指示完成一些特定的动作,并且所定义的很多指示字是编译器特有的。

#pragma在不同的编译器间是不可移植的
——预处理器将忽略它不认识的#pragma指令
——不同的编译器可能以不同的方式解释一条#pragma指令。

一般用法:

	#pragma parameter
	注:不同的parameter参数语法和意义各不相同
message参数在大多数的编译器中都有相似的实现;

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

与#error和#warning不同,#pragma message仅仅代表一条编译消息,不代表程序错误。

#include <stdio.h>

#if defined(ANDROID20)
    #pragma message("Compile Android SDK 2.0...")
    #define VERSION "Android 2.0"
#elif defined(ANDROID23)
    #pragma message("Compile Android SDK 2.3...")
    #define VERSION "Android 2.3"
#elif defined(ANDROID40)
    #pragma message("Compile Android SDK 4.0...")
    #define VERSION "Android 4.0"
#else
    #error Compile Version is not provided!
#endif

int main()
{
    printf("%s\n", VERSION);

    return 0;
}

在Linux下使用GCC进行编译:

~/will$ gcc 24-1.c   //直接编译
24-1.c:13: error: #error Compile Version is not provided!
24-1.c: In function ‘main’:
24-1.c:18: error: ‘VERSION’ undeclared (first use in this function)
24-1.c:18: error: (Each undeclared identifier is reported only once
24-1.c:18: error: for each function it appears in.)
~/will$ 
~/will$ 
~/will$ gcc -DANDROID23  24-1.c   // 条件编译
24-1.c:7: note: #pragma message: Compile Android SDK 2.3...    //与VC不同的是,BCC和GCC将 #pragma message: 打印出来
~/will$ 
~/will$ 
~/will$ ./a.out   //运行
Android 2.3

#pragma once

#pragma once 用于保证头文件纸杯编译一次;

#pragma once 是编译器相关,不一定被支持。


pragma once是部分编译器支持;预处理器遇见pragma once后将直接忽略再次出现的头文件

#pragma pack  内存对齐

——不同类型的数据在内存中按照一定的规则排列
——而不一定是顺序的一个接一个的排列

为什么需要内存对齐?
——CPU对内存的读取不是连续的,而是分成块读取的,快的大小只能是1,2,4,8,16...字节;
——当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣;
——某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常。

#pragma pack用于指定“内存对齐”方式。

#include <stdio.h>

#pragma pack(4)

struct Test1
{    		        //对齐参数	 偏移地址		大小
	char  c1;     //1    		0			1(4)
    short s;          //2   		2			2   
    char  c2;         //1    		4			1(4)
    int   i;          //4    		8			4
};
#pragma pack()
#pragma pack(4)
struct Test2
{		 //对齐参数	        偏移地址		        大小
    char  c1;    //1     		0			1
    char  c2;    //1     		1			1
    short s;     //2     		2			2
    int   i;     //4     		4			4
};
#pragma pack()
int main()
{
    printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
    printf("sizeof(Test2) = %d\n", sizeof(struct Test2));

    return 0;
}

编译运行:

~/will$ ./a.out
sizeof(Test1) = 12
sizeof(Test2) = 8

Gcc编译器暂时不支持8字节对齐

struct占用的内存大小:
——第一个成员起始于0偏移处;
——每个成员按其类型大小和pack参数中较小的一个进行对齐;
偏移地址必须能被对齐参数整除
结构体成员的大小取其内部长度最大的数据成员作为其大小;

结构体总长度必须为所有对齐参数的整数倍

注意:编译器在默认情况下按照4字节对齐。
#include <stdio.h>
#pragma pack(8)
struct S1
{               //对齐参数      偏移地址        大小
    short a;    //2             0            2  
    long b;     //4             4            4
};
struct S2
{                   //对齐参数      偏移地址        大小
    char c;         //1             0              1
    struct S1 d;    //4             4              8
    double e;       //8             16             8
};

#pragma pack()
int main()
{
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    return 0;

}
Gcc编译器暂时不支持8字节对齐,输出为
8
20
在vc编译器支持8字节对齐,输出为
8
24

小结:

#pragma用于指示编译器完成一些特定的动作

 #pragma所定义的很多指示字是编译器特有

——#pragma message用于自定义编译消息
——#pragma once用于保证头文件只被编译一次
——#pragma pack用于指定内存对齐方式


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章