#pragma 使用分析

目录

1、#pragma简介 

2、#pragma message 

3、#pragma once

4、#pragma pack


1、#pragma简介 

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

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

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

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

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

一般用法: 

                           #pragma parameter 

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

 

2、#pragma message 

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

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

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

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

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

实例分析

#pragma message使用示例    test.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;  
}

gcc

            

VS2015

           

BCC

           

 

3、#pragma once

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

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

   

                                              这两种方式有什么区别?

                通过宏可以保证头文件里的内容只被嵌入一次但可能包含了多次,预处理

                器依然处理了多次,所以从效率上说它要打折扣,而pragam once 告诉

                预处理器当前文件只被编译一次(即只被include一次,多余的都不会处理),

                所以它的编译效率会高很多,然而大多数工程使用#ifndef方式,原因在于

                不是所有的编译器都支持once这个参数,#ifndef是C语言所支持的

实例分析 

#pragma once使用分析    test.c

global.h

#pragma once  
  
int g_value = 1;  

  test.c

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

 

在VS2015同样支持,然而在BCC5.5.1会报错,即不支持once参数

global.h

#ifndef _GLOBAL_    
#define _GLOBAL_    
        
#pragma once    
          
int g_value = 1;    
#endif  

实际工程中往往用这种方式保证移植性和高效性

此时在BCC5.5.1上可以编译成功

4、#pragma pack

什么是内存对齐? 

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

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

    

                   Test1和Test2所占的内存空间是否相同?

                               

 

                        

 

为什么需要内存对齐? 

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

                        块的大小只能是1、2, 4, 8, 16 .. 字节 

                    -当读取操作的数据未对齐,则需要两次总线周期来访

                        问内存,因此性能会大打折扣 

                    -某些硬件平台只能从规定的相对地址处读取特定类型的

                        数据,否则产生硬件异常 

例题:

 

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

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

   

        

 

struct占用的内存大小 

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

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

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

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

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

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

                   

编程实验

结构体大小计算 

test.c

#include <stdio.h>  
  
#pragma pack(2)  
struct Test1  
{  
    char  c1;  //1 0 1 
    short s;   //2 2 2  
    char  c2;  //1 4 1  
    int   i;   // 2 6 4//10 
};  
#pragma pack()  
  
#pragma pack(4)  
struct Test2  
{  
    char  c1;  
    char  c2;  
    short s;  
    int   i;  
};  
#pragma pack()  
  
int main()  
{  
    printf("sizeof(Test1) = %d\n", sizeof(struct Test1));  
    printf("sizeof(Test2) = %d\n", sizeof(struct Test2));  
  
    return 0;  
} 

   

 

test.c(微软面试题)

#include <stdio.h>  
  
#pragma pack(8)  
  
struct S1  
{  
    short a;   //2 0 2
    long b;  //4 4 4-->8   这里按long为4
};  
  
struct S2  
{  
    char c;  //1  0  1
    struct S1 d;  //4  4  8   // 结构体成员的大小取其内部长度最大的数据成员作为其大小和pack参数对比 ,对齐参数为4
    double e;  //   8  16  8--->24
};  
  
#pragma pack()  
  
int main()  
{  
    printf("%d\n", sizeof(struct S1));  
    printf("%d\n", sizeof(struct S2));  
  
    return 0;  
}  

                                           gcc version 6.3.0 

  

            说明这个版本编译器不支持pack参数,用的默认参数,4,结果为20         

                        

VS2015(BCC)

                                    

小结

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

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

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

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

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

 

 

扩展:
#pragma comment( comment-type,  ["commentstring"] )

comment-type:可选项compliler,lib,linker,exestr,最常用的是lib

如:#pragma comment(lib, "A.lib")  将A静态库加入本工程

否者我们就需要将A.h和A.lib分别放入...\VC\include\和...\VC\lib\目录下,再自己配置IDE链接时加上该库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值