欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言 詳細(xì)講解#pragma的使用方法

 更新時(shí)間:2022年04月19日 10:59:07   作者:清風(fēng)自在 流水潺潺  
#pragma 指令對(duì)每個(gè)編譯器給出了一個(gè)方法,在保持與C和C++語(yǔ)言完全兼容的情況下,給出主機(jī)或操作系統(tǒng)專有的特征。依據(jù)定義,編譯指示是機(jī)器或操作系統(tǒng)專有的, 且對(duì)于每個(gè)編譯器都是不同的

一、#pragma 簡(jiǎn)介

#pragma 用于指示編譯器完成一些特定的動(dòng)作

#pragma 所定義的很多指示字是編譯器特有的

#pragma 在不同的編譯器間是不可移植的

  • 預(yù)處理器將忽略它不認(rèn)識(shí)的 #pragma 指令
  • 不同的編譯器可能以不同的方式解釋同一條 #pragma 指令

一般用法:

#pragma parameter

注:不同的 parameter 參數(shù)語(yǔ)法和意義各不相同

二、#pragma message

  • message 參數(shù)在大多數(shù)的編譯器中都有相似的實(shí)現(xiàn)
  • message 參數(shù)在編譯時(shí)輸出消息到編譯輸出窗口中
  • message 用于條件編譯中可提示代碼的版本信息

例如:

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

注:#error 和 #warning 不同,#pragma message 僅僅代表一條編譯消息,不代表程序錯(cuò)誤。

下面看一個(gè) #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;
}

下面為輸出結(jié)果:

三、#pragma once

  • #pragma once 用于保證頭文件只被編譯一次
  • #pragma once 是編譯器相關(guān)的,不一定被支持

下面兩種方式的區(qū)別是:前者是被 C 語(yǔ)言所支持的,并不是只包含一次頭文件,而是包含多次,然后通過(guò)宏控制是否嵌入到源代碼中,也就是說(shuō)通過(guò)宏的方式,可以保證頭文件里面的內(nèi)容只被嵌入一次,但是由于包含了多次,預(yù)處理器還是處理了多次,所以效率上來(lái)說(shuō)比較低;后者是告訴預(yù)處理器當(dāng)前文件只編譯一次,所以說(shuō)效率較高。

下面看一個(gè) #pragma once 的使用示例:

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

下面為輸出結(jié)果,可以看到雖然在test.c 定義了兩次global.h,但是程序編譯沒(méi)有報(bào)錯(cuò),且能正常運(yùn)行,這就是 #pragma once 作用的結(jié)果:

工程應(yīng)用中既想要移植性,又想要保證效率,可以采用以下做法:

global.h:

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

四、#pragma pack

什么是內(nèi)存對(duì)齊?

  • 不同類型的數(shù)據(jù)在內(nèi)存中按照一定的規(guī)則排列
  • 而不一定是順序的一個(gè)接一個(gè)的排列

下面想想 Test1 和 Test2 所占的內(nèi)存空間是否相同?

答案是否定的,Test1 占用 12 個(gè)字節(jié),而 Test 占用 8 個(gè)字節(jié)

為什么需要內(nèi)存對(duì)齊?

  • CPU對(duì)內(nèi)存的讀取不是連續(xù)的,而是分成塊讀取的,塊的大小只能是1、2、4、8、16...字節(jié)
  • 當(dāng)讀取操作的數(shù)據(jù)未對(duì)齊,則需要兩次總線周期來(lái)訪問(wèn)內(nèi)存,因此性能會(huì)大打折扣
  • 某些硬件平臺(tái)只能從規(guī)定的相對(duì)地址處讀取特定類型的數(shù)據(jù),否則產(chǎn)生硬件異常

#pragma pack 用于指定內(nèi)存對(duì)齊方式

#pragma pack 能夠改變編譯器的默認(rèn)對(duì)齊方式

例如,下面代碼中,Test1 和 Test2 的內(nèi)存均為 8 個(gè)字節(jié)

struct 占用的內(nèi)存大小

第一個(gè)成員起始于 0 偏移處

每個(gè)成員按其類型大小和 pack 參數(shù)中較小的一個(gè)進(jìn)行對(duì)齊

  • 偏移地址必須能被對(duì)齊參數(shù)整除
  • 結(jié)構(gòu)體成員的大小取其內(nèi)部長(zhǎng)度最大的數(shù)據(jù)成員作為其大小

結(jié)構(gòu)體總長(zhǎng)度必須為所有對(duì)齊參數(shù)的整數(shù)倍

編譯器在默認(rèn)情況下按照 4 字節(jié)對(duì)齊。

下面通過(guò)代碼,手工計(jì)算結(jié)構(gòu)體所占用的內(nèi)存大小

test.c:

#include <stdio.h>
 
#pragma pack(4)
struct Test1
{                   //對(duì)齊參數(shù)      偏移地址        大小
    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
{                   //對(duì)齊參數(shù)      偏移地址        大小
    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;
}

以 Test1 為例,c1 類型大小為 1 字節(jié),而 pack 參數(shù)默認(rèn)為 4,所以對(duì)齊參數(shù)取最小為 1;同理 s 的對(duì)齊參數(shù)為 2,偏移地址要被 2 整除,所以為 2;同理 c 的對(duì)齊參數(shù)為 1,偏移地址為 4;同理,i 的對(duì)齊參數(shù)為 4,因?yàn)槠频刂芬鼙?對(duì)齊參數(shù) 4 整除,在偏移地址 4 之后能被 4 整除的最小偏移地址為 8,所以 i 的偏移地址為 8,而 i 占用 4 個(gè)字節(jié),所以 Test1 結(jié)構(gòu)體占用的總字節(jié)數(shù)為 12 字節(jié),這就和上面的圖對(duì)應(yīng)起來(lái)了。

下面再通過(guò)一個(gè)例子感受一下:

在 gcc 編譯器下,test.c:

#include <stdio.h>
 
#pragma pack(8)
 
struct S1
{                   //對(duì)齊參數(shù)      偏移地址        大小
    short a;        //2            0              2
    long b;         //4            4              4
};
 
struct S2
{                   //對(duì)齊參數(shù)      偏移地址        大小
    char c;         //1            0              1
    struct S1 d;    //4            4              8
    double e;       //4            12             8
};
 
#pragma pack()
 
int main()
{
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
 
    return 0;
}
 

下面為輸出結(jié)果:

這里注意兩點(diǎn):

1.結(jié)構(gòu)體成員的大小取其內(nèi)部長(zhǎng)度最大的數(shù)據(jù)成員作為其大小,所以 S1 的內(nèi)存大小為 4,而pack 參數(shù)默認(rèn)為 8,所以對(duì)齊參數(shù)為 4

2.一般的 pack 對(duì)齊格式分別是 1,2,4,8,16,默認(rèn)的對(duì)齊格式,也就是:#pragmapack() 的情況下,會(huì)在結(jié)構(gòu)體中挑選占用字節(jié)最多的類型,例如 double 占用 8 個(gè)字節(jié)

3.gcc 編譯器暫時(shí)不支持 8 字節(jié)對(duì)齊,默認(rèn)按照 4 字節(jié)對(duì)齊,所以 S2 中的 e 的對(duì)齊參數(shù)為 4,故 S2 占用內(nèi)存大小為 20 字節(jié)。(學(xué)習(xí)采用的為 ubuntu 10.10)

如果把代碼放在 VS2012 里運(yùn)行,那結(jié)果就是和分析的一樣,S2 占用 24 字節(jié)。

#include <stdio.h>
 
#pragma pack(8)
 
struct S1
{                   //對(duì)齊參數(shù)      偏移地址        大小
    short a;        //2            0              2
    long b;         //4            4              4
};
 
struct S2
{                   //對(duì)齊參數(shù)      偏移地址        大小
    char c;         //1            0              1
    struct S1 d;    //4            4              8
    double e;       //8            16             8
};
 
#pragma pack()
 
int main()
{
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
 
    return 0;
}
 

結(jié)果:

五、小結(jié)

#pragma 用于指示編譯器完成一些特定的動(dòng)作

#pragma 所定義的很多指示字是編譯器特有的

  • #pragma message 用于自定義編譯消息
  • #pragma once 用于保證頭文件只被編譯一次
  • #pragma pack 用于指定內(nèi)存對(duì)齊方式

到此這篇關(guān)于C語(yǔ)言 詳細(xì)講解#pragma的使用方法的文章就介紹到這了,更多相關(guān)C語(yǔ)言 #pragma內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論