欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言学习笔记14——#pragma使用分析

程序员文章站 2022-05-05 10:25:55
...

#pragma简介

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

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

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

    • 预处理器将忽略他不认识的#pragma指令
    • 不同的编译器可能以不同的方式解释同一条#pragma指令

用法:

#pragma parameter

注:不同的parameter参数语法和意义各不相同


#pragma的分析1:#pragma message

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

  • 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;
}

运行结果

delphi@delphi-vm:~$ gcc -DANDROID20 text.c
text.c:5: note: #pragma message: Compile Android SDK 2.0...
delphi@delphi-vm:~$ ./a.out
Android 2.0

#pragma的分析2:#pragma once

  • #pragma once 用于保证头文件只被编译一次
  • #pragma once 是编译器相关的, 不一定被支持
/*
  测试代码

  global.h
*/

#pragma once

int g_value = 1;
/*
  测试代码

  主程序
  main.c
*/

#include <stdio.h>
#include "global.h"
#include "global.h"

int main()
{
    printf("g_value = %d\n", g_value);

    return 0;
}

运行结果

g_value = 1

#pragma的分析3:#pragma pack

#pragma pack 用于指定内存对齐方式
  • 什么是内存对齐?

    • 不同类型的数据在内存中按照一定的规律排列

    • 不一定是顺序的一个一个的排列

  • 为什么需要内存对齐?

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

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

    • 某些硬件平台只能从常规的相对地址读取特定类型的数据, 否则产生硬件异常

  • 如何内存对齐?

    • 编译器在默认情况下按照 4字节对齐(#pragma pack(4))

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

  • 计算struct占用的内存大小

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

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

    • 偏移地址必须能被对齐参数整除

    • 结构体类型大小取其内部长度最大的数据成员作为其大小

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

/*
  测试代码

  结构体默认对齐方式为 4 字节

  因为内存对齐, struct Test1 和 struct Test2 内成员相同, 但占用的内存不同
*/

#include <stdio.h>

struct Test1
{                   // 对齐参数       偏移地址     占内存大小
    char  c1;       // 1             0           1
    short s;        // 2             2           2
    char  c2;       // 1             4           1
    int   i;        // 4             8           4
};                  // sizeof(struct Test1) == 8 + 4 == 12 

struct Test2
{                   // 对齐参数       偏移地址     占内存大小
    char  c1;       // 1             0           1
    char  c2;       // 1             1           1
    short s;        // 2             2           2
    int   i;        // 4             4           4
};                  // sizeof(struct Test2) == 4 + 4 == 8

int main()
{
    printf("sizeof(Test1) = %d\n", sizeof(struct Test1));       // sizeof(Test1) = 12
    printf("sizeof(Test2) = %d\n", sizeof(struct Test2));       // sizeof(Test2) = 8

    return 0;
}

/*
  测试代码

  利用 #pragma pack 改变默认对齐方式
  重新计算 struct Test1 和 struct Test2 占用的内存大小
*/

#include <stdio.h>

#pragma pack(1)
struct Test1
{                   // 对齐参数       偏移地址     占内存大小
    char  c1;       // 1             0           1
    short s;        // 1             1           2
    char  c2;       // 1             3           1
    int   i;        // 1             4           4
};                  // sizeof(struct Test1) == 4 + 4 == 8
#pragma pack()

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

int main()
{
    printf("sizeof(Test1) = %d\n", sizeof(struct Test1));       // 8
    printf("sizeof(Test2) = %d\n", sizeof(struct Test2));       // 8

    return 0;
}
相关标签: C #pragma