【C】24.#pragma 使用分析

#pragma

一般用法

#pragma parameter

不同的 parameter 参数语发和意义不相同, 不同编译器对它有不同的编译方式.

,

#pragma message

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

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

在不同的编译器效果不一样

[GCC]  test.c:10: note: #pragma message: Compile Android SDK 4.0...
[VC]   Compile Android SDK 4.0...

#pragma once

#ifndef __HEAD_FILE_
#define __HEAD_FILE_
// ...
#endif

VS 

#pragma once

#pragma once 效率高,但是在不同的编译器有不同的表现,比如在GCC下是被支持的 BCC是不支持的。

一个保证适用不同编译器又保证效率的写法,这样的移植更好!!

#ifndef __HEAD_FILE_
#define __HEAD_FILE_
#pragma once
// ...
#endif

#pragma Pack

内存对齐(嵌入式开发中很重要的一个)

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

struct Test1
{
    char  c1;
    short s;
    char  c2;
    int   i; 
};

struct Test2
{
    char  c1;
    char  c2;
    short s;
    int   i;
};

Test1 和 Test2 内存分布的方示意图

造成这样的原因是因为:

CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1,2,4,8,16 字节,当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣,因此编译器编译的时候会使它对齐,提高读取速度。某些硬件平台只能从规定的相对地址读取特定类型的数据,否则会产生硬件异常。

#pragma Pack 用于指定内存对齐方式

规则:Struct占用的内存大小:

  • 第一个成员起始于0偏移处
  • 每个成员按其类型大小和pack参数中较小一个作为(对齐参数)
  • 偏移地址必须能被 对齐参数整除,
  • 结构体成员的大小取其内部长度最大的数据成员作为其大小。
  • 结构体总长度必需为所有对齐参数的整数倍

注意:

上一个偏移地址+大小,作为下一个参数的偏移地址(当然还要判断偏移地址能不能作为的条件)最终的占用的大小是最后变量的偏移地址+大小(当然还要计算:结构体总长度必需为所有对齐参数的整数倍).

练习一

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

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

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

练习二:

#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;       //    4        12       8
};

#pragma pack()
S1  8字节
S2  20字节

练习二中 GCC编译器暂时不支持8字节对齐 #pragma pack(8),因为不支持就直接按照4字节对齐#pragma pack(4)

小结

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

  • #pragma message 用于自定义编译消息
  • #pragma once 用于保证头文件只被编译一次
  • #pragma pack 用于指定内存对齐方式
发布了84 篇原创文章 · 获赞 0 · 访问量 762

猜你喜欢

转载自blog.csdn.net/zhabin0607/article/details/103295298