24-#pragma使用分析

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:4.4.5

一、#pragme简介

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

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

3)#pragme在不同的编译器间是不可抑制的

      - 预处理器将忽略它不认识的#pragma指令

      - 不同的编译器可能以不同的方式解释同一条#pragma指令

      一般用法

      #pragma parameter

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

二、#pragma message

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

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

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

#if defined(ANDROID20)
    #pragma message("Compile Android SDK 2.0...")
    #define VERSION "Android 2.0"
#endif

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

实例分析
#pragma message使用示例
24-1.c

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

操作:

1)gcc 24-1.c -0 24-1.out编译报错

2)gcc -DANDROID20 24-1.c -o 24-1.out编译有提示:

24-1.c:4:10: note: #pragma message: Compile Android SDK 2.0...
    #pragma message("Compile Android SDK 2.0...")
提示:编译安卓SDK2.0......

运行结果:

Android 2.0

知识点:

#if defined(val)--有val定义,defined返回1,预编译条件判断正确。

三、#pragma once

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

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

实例分析
#pragma once使用分析
24-2.c

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

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

    return 0;
}

global.h
#ifndef _GLOBAL_H_
#define _GLOBAL_H_

#pragma once

int g_value = 1;

#endif

操作:

1)gcc 24-2.c -o 24-2.out编译正确,打印结果:

g_value = 1

分析:

         #pragma once是编译器相关的,比如bcc编译器不支持。

四、#pragma pack

1)什么是内存对齐?

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

       - 而不一定是顺序的一个接一个的排列

2)为什么需要内存对齐?

      - CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是

      1、2、4、8、16……字节

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

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

3)#pragma pack用于指定内存对齐方式

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

5)struct占用的内存大小

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

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

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

          * 结构体成员的大小取其内部长度最大的数据成员作为对齐

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

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

24-3.c
#include <stdio.h>

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

操作:

1)#pragma pack(4): gcc 24-3.c -o 24-3.out编译正确,打印结果:

sizeof(Test1) = 12
sizeof(Test2) = 8

2)#pragma pack(1):gcc 24-3.c -o 24-3.out编译正确,打印结果:

sizeof(Test1) = 8
sizeof(Test2) = 8
24-4.c
#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;    //4          16         8
};
#pragma pack()

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

操作:

1)使用默认的4字节对齐:gcc 24-4.c -o 24-4.out编译正确,打印结果:

8
20

2)使用8字节对齐:gcc 24-4.c -o 24-4.out编译正确,打印结果:

8
20

bcc编译器:

8
24

分析:

        使用#pragma用于指示编译器完成一些特定的动作,编译器对支持的动作进行处理,不支持的动作没有任何反馈信息。不能过度依赖编译器进行优化。

小结:

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

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

      - #pragma message用于定义编译消息

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

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

发布了40 篇原创文章 · 获赞 1 · 访问量 1758

猜你喜欢

转载自blog.csdn.net/piaoguo60/article/details/104058325
今日推荐