C语言#pragma使用方法

本文介绍了C语言中的#pragma预处理指令,包括用于自定义编译信息的#pragma message,确保头文件只被编译一次的#pragma once,以及控制结构体内存对齐的#pragma pack。通过示例代码展示了#pragma pack如何影响结构体的内存布局,并指出#pragma指令在不同编译器间的不可移植性。

C语言#pragma使用方法

1.总结

1、#pragma用于指示编译器完成一些特定的动作
2、#pragma所定义的很多指示字是编译器特有的(每种编译可能都不一样)
(1) #pragma message 用于自定义编译信息
(2)#pragma once 用于保证头文件只被编译一次
(3)#pragama pack用于指定内存对齐(一般用在结构体)
struct占用内存大小
1)第一个成员起始于0偏移处
2)每个成员按其类型大小和pack参数中较小的一个进行对齐
——偏移地址必须能被对齐参数整除
——结构体成员的对齐参数(注意是对齐参数,而不是结构体长度)取其内部长度最大的数据成员作为其大小
3)结构体总长度必须为所有对齐参数的整数倍
编译器在默认情况下按照4字节对齐
3、#pragma在不同的编译器间是不可移植的
(1)预处理器将忽略它不认识#pragma指令
(2)不同的编译器可能以不同的方式解释同一条#pragma指令
二、代码测试
1、#pragma message:自定义编译信息输出到终端(一般和#if配合使用,用在控制版本号)

#include <stdio.h>
#define ANDROID20
 
#if defined ANDROID20
   #pragma message "Compile Android SDK 2.0..."
   #define VERSION "Android 2.0"
#elif defined ANDROID30
   #pragma message "Compile Android SDK 3.0..."
   #define VERSION "Android 3.0"
#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;
}

//#include <stdio.h>
//#define ANDROID20

//#if defined ANDROID20
//   #pragma message "Compile Android SDK 2.0..."
//   #define VERSION "Android 2.0"
//#elif defined ANDROID30
//   #pragma message "Compile Android SDK 3.0..."
//   #define VERSION "Android 3.0"
//#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;
//}

#if 0
#include <stdio.h>
#include "test.h"
#include "test.h"

int main()
{
    printf("g_value = %d\n",g_value);
    return 0;
}
#endif

#include <stdio.h>

#pragma pack(2)
struct test1
{                 //对齐参数  偏移地址   大小
    char c1;      //1          0       1
    char c2;      //1          1       1
    short s;      //2          2       2
    int i;        //2          4       4
};
#pragma pack()

#pragma pack(4)
struct test2
{                 //对齐参数  偏移地址   大小
    char c1;      //1          0       1
    short s;      //2          2       2
    char c2;      //1          4       1
    int i;        //4          8       4
};
#pragma pack()

#pragma pack(8)
struct S1
{                 //对齐参数  偏移地址   大小
    short s;      //2          0       2
    long l;       //4          4       4
};
struct S2
{                 //对齐参数  偏移地址   大小
    char c;       //1          0       1
    struct S1 d;  //4          4       8
    double e;//理论//8         16       8    这里实际是错误的,gcc不支持8字节对齐,所以这里默认是4字节对齐           //实际//4         12       8    所以整个占用内存是20字节
};
#pragma pack()

int main()
{
    printf("sizeof(struct test1) = %d\n",sizeof(struct test1));  //输出8
    printf("sizeof(struct test2) = %d\n",sizeof(struct test2));  //输出12

    printf("sizeof(struct S1) = %d\n",sizeof(struct S1));        //输出8
    printf("sizeof(struct S2) = %d\n",sizeof(struct S2));        //理论计算应该输出24  但是实际打印输出是20   这是因为gcc不支持8字节内存对齐,所以这里是默认4字节对齐,
    return 0;
}

`#pragma` 是 C 语言中的预处理指令,用于指示编译器完成一些特定的动作。它所定义的很多指示字是编译器特有的,后面的参数决定其具体功能。`#pragma` 在不同的编译器间是不可移植的,预处理器会忽略它不认识的 `#pragma` 指令,不同编译器可能以不同的方式解释同一条 `#pragma` 指令[^1]。以下是一些常见的 `#pragma` 指令及其用法: ### 1. `message` 参数 该参数用于在编译时输出自定义消息,有助于调试和提示。 ```c #pragma message("编译时会输出此消息") ``` ### 2. `code_seg` 参数 `code_seg` 用于指定函数或代码段存储的位置。 ```c #pragma code_seg(".mycode") void myFunction() { // 此函数代码将存储在.mycode段 } #pragma code_seg() // 恢复默认段 ``` ### 3. `once` 参数 `#pragma once` 用于确保头文件只被编译一次,类似于 `#ifndef`、`#define`、`#endif` 这种宏定义的头文件保护机制。 ```c // header.h #pragma once // 头文件内容 ``` ### 4. `pack` 参数 `pack` 用于指定结构体、联合体成员的对齐方式。 ```c #pragma pack(1) // 按1字节对齐 struct MyStruct { char a; int b; }; #pragma pack() // 恢复默认对齐 ``` ### 5. `section` 指令参数 `#pragma GCC section` 用于指定变量或函数存放的特定段。 ```c #pragma GCC section text ".mcal_text" const int ab = 10; #pragma GCC section text ``` ### 6. `warning` 参数 `warning` 用于控制编译器警告信息的显示方式。 ```c #pragma warning(disable:4507 34) // 不显示4507和34号警告信息 #pragma warning(once:4385) // 4385号警告信息仅报告一次 #pragma warning(error:164) // 把164号警告信息作为一个错误处理 ``` ### 7. `comment` 参数 `comment` 用于将注释信息添加到目标文件中。 ```c #pragma comment(lib, "mylib.lib") // 链接时链接指定库文件 ``` ### 8. `hdrstop` `#pragma hdrstop` 表示预编译头文件到此为止,后面的头文件不进行预编译。BCB 可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。 ```c #include <stdio.h> #pragma hdrstop #include <custom_header.h> // 此头文件不预编译 ``` ### 9. `startup` 和 `package(smart_init)` 有时单元之间有依赖关系,比如单元 A 依赖单元 B,所以单元 B 要先于单元 A 编译。可以用 `#pragma startup` 指定编译优先级,如果使用了 `#pragma package(smart_init)`,BCB 就会根据优先级的大小先后编译[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值