17 pragma

1 pragma 简介

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

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

  • #pragma 在不同的编译器间是不可移植的

    • 预处理器将忽视它所不认识的 #pragma 指令
    • 不同的编译器可能以不同的方式解释同一条 #pragma 指令
  • 一般用法

    • 不同的 parameter 参数语法和意义各不相同
    #pragma parameter
    

2 #pragma message

  • message 参数在大多数的编译器中都有相似的实现

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

  • message 用于条件编译中可提示代码的版本信息

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

  • #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
    ", VERSION);
    
        return 0;
    }
    //编译:gcc -DANDROID40 test.c -o test
    test.c:10: note: #pragma message: Compile Android SDK 4.0...
    //运行结果
    Android 4.0
    

3 #pragma once

  • #pragma once 用于保证头文件只被编译一次

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

  • #pragma once 使用示例

    #include <stdio.h>
    #include "global.h"
    #include "global.h"
    
    int main()
    {
        printf("g_value = %d
    ", g_value);
    
        return 0;
    }
    
    //global.h
    #pragma once
    
    int g_value = 1;
    

4 #pragma back

  • 内存对齐

    • 不同类型的数据在内存中按照一定的规则排列,而不一定是顺序的一个接一个的排列
    #include <stdio.h>
    
    struct Test1
    {
        char  c1;
        short s;
        char  c2;
        int   i; 
    };
    
    struct Test2
    {
        char  c1;
        char  c2;
        short s;
        int   i;
    };
    
    int main()
    {
        printf("sizeof(Test1) = %d
    ", sizeof(struct Test1));  //12
        printf("sizeof(Test2) = %d
    ", sizeof(struct Test2));  //8
    
        return 0;
    }
    
  • 为什么需要内存对齐?

    • CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1,2,4,8,16...字节
    • 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
    • 某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则会产生硬件异常
  • #pragma back 用于指定内存对齐方式,能够改变编译器的默认对齐方式

  • strcut 占用的内存大小

    • 第一个成员起始于 0 偏移处

    • 每个成员按其类型大小和 pack 参数中较小的一个进行对齐

      • 偏移地址必须能被对齐参数整除
      • 结构体成员的大小取其内部长度最大的数据成员作为其大小(仅在计算对齐参数比较时
    • 结构体总长度必须为所有对齐参数的整数倍

  • 编译器在默认情况下按照 4 字节对齐

  • GCC 不支持 #pragma pack(8)

  • 结构体大小计算

    • Demo1
    #include <stdio.h>
    
    #pragma pack(2)
    struct Test1
    {              //对齐参数    偏移地址    大小
        char  c1; //1           0          1
        short s;  //2           1—>2       2
        char  c2; //1           4          1
        int   i;  //2           5->6       4
    };
    #pragma pack()
    
    #pragma pack(4)
    struct Test2
    {
        char  c1;
        char  c2;
        short s;
        int   i;
    };
    #pragma pack()
    
    int main()
    {
        printf("sizeof(Test1) = %d
    ", sizeof(struct Test1));  //
        printf("sizeof(Test2) = %d
    ", sizeof(struct Test2));  //
    
        return 0;
    }
    
    • Demo2
    #include <stdio.h>
    
    #pragma pack(8)
    
    //8字节
    struct S1
    {              //对齐参数    偏移地址    大小
        short a;   //2          0          2
        long b;    //4          2->4       4
    };
    
    //24字节
    struct S2
    {                 //对齐参数    偏移地址    大小
        char c;       //1          0         1
        struct S1 d;  //4          1->4      8
        double e;     //8          12->16    8
    };
    
    #pragma pack()
    
    int main()
    {
        printf("%d
    ", sizeof(struct S1));
        printf("%d
    ", sizeof(struct S2));
    
        return 0;
    }
    
原文地址:https://www.cnblogs.com/bky-hbq/p/13646494.html