zoukankan      html  css  js  c++  java
  • C语言-第19课

    第19课 - #pragma预处理分析

     

    1. #pragma简介

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

    (2) #pragma所定义的很多指示字是编译器和操作系统特有的

    (3) #pragma在不同的编译器间是不可移植的。

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

    两个不同的编译器可能以两种不同的方式解释同一条#pragma指令。

    一般用法:#pragma parameter

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

     

    1. #pragma message

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

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

    (3) message可用于代码的版本控制。

    注意messageVC特有的编译器指示字,GCC中将其忽略。

     

    例子:#pragma在不同编译器下的使用示例

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

    }

    为了在VC中,显示像在linux下面一样的结果。我们在工程-设置中,添加相应的变量ANDROID23,就会显示我们要的结果了。

    linux下面,gccg++是识别不了pragma

     

    1. #pragma pack

    1)什么是内存对齐?

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

    #include <stdio.h>

     

    int main()

    {   

    struct Test1

    {           //   起始    大小   空

    char c1;  //   0        1   

    short s;  //    2        2    1

    char c2;  //   4        1     3

    int i;    //    8        4

    };

     

    struct Test2

    {

    char c1;  //   0        1    

    char c2;  //   1        1

    short s;  //   2         2

    int i;     //   4        4

    };

    printf("%d ",sizeof(struct Test1));

    printf("%d ",sizeof(struct Test2));

     

    }

    运行结果:12

                      8

     

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

    l CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是124816字节。

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

    l 某些硬件平台只能从规定的地址处取某些特定类型的(偶地址)数据,否则抛出硬件异常。

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

     

    #include <stdio.h>

    int main()

    {   

    struct Test

    {

    char c1;

    short s;

    char c2;

    int i;

    };

     

    #pragma pack(2)

    struct Test1

    {

    char c1;

    short s;

    char c2;

    int i;

    };

    #pragma pack

     

     

    #pragma pack(4)

    struct Test2

    {

    char c1;

    char c2;

    short s;

    int i;

    };

    #pragma pack

     

    printf("%d ",sizeof(struct Test));   //系统默认是4个字节对齐

    printf("%d ",sizeof(struct Test1));

    printf("%d ",sizeof(struct Test2));

     

    }

    运行结果:12

                      10

                      8

     

    1. struct占用的内存大小

    1)第一个成员起始于0偏移处。

    2)每个成员按其类型大小和指定对齐参数n中较小的一个进行对齐。

    l 偏移地址和成员占用大小均需对齐。

    l 结构体成员的对齐参数为其所有成员使用的对齐参数的最大值。

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

     

    Intel和微软的面试题--结构体大小的计算

    #include <stdio.h>

    #pragma pack(8)

    struct S1

    {                 //  起始  大小    空

        short a;      //  0      2  

        long b;       //  4      4       2

    };

    struct S2

    {

        char c;      //  0       1     

        struct S1 d;   //  4       8      3             

        double e;    //  16      8      4

    };  //对于结构体选它的对齐大小要选它结构中,最大的数据大小。

     

    #pragma pack()

    int main()

    {

        struct S2 s2;  

        printf("%d ", sizeof(struct S1));

        printf("%d ", sizeof(struct S2));

        printf("%d ", (int)&(s2.d) - (int)&(s2.c));

    /*dc的起始地址查了4,所以结果是4 */

        return 0;

    }

    运行结果:8

                     24

                     4

    linux下运行是 8204,因为在linux下面会变成默认的4字节对齐。

    struct S2

    {

        char c;      //  0       1     

        struct S1 d;   //  4       8      3             

        double e;    //  12      8      0

    };  //对于结构体选它的对齐大小要选它结构中,最大的数据大小。

    我们看一下12的选取,double类型占8个字节,8字节和4字节(对齐字节)进行比较,选小的4。找4的最小超过的公倍数12

     

    课后思考:

    问:

    结构体变量是否可以直接用memcmp函数进行相等判断?

    答:

    如果结构体内都是基本的数据成员,那是可以的,例如常见的 POINT 结构,RECT结构等,可以用memcmp进行相等判断;
    如果结构体中不全是基本数据成员,例如结构体中有个CString 成员,那就不能这样判断了。
    所以具体要看你的结构体定义,不能一概而论

  • 相关阅读:
    GIT → 04:Git与代码托管平台
    GIT → 03:Git的下载和安装
    GIT → 02:Git和Svn比较
    GIT → 01:学习版本控制的原因
    GIT → 00:GIT学习大纲
    GIT → 10:基于IntelliJ IDEA的Git 操作
    GIT → 11:Git 工作流与实战演练
    GIT → 09:TortoiseGit 图形化工具
    亚马逊服务器搭建pptp方法
    Safari获取UDID需要安装.mobileconfig文件,
  • 原文地址:https://www.cnblogs.com/free-1122/p/9720727.html
Copyright © 2011-2022 走看看