日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C語言?詳細講解#pragma的使用方法_C 語言

作者:清風自在?流水潺潺 ? 更新時間: 2022-06-18 編程語言

一、#pragma 簡介

#pragma 用于指示編譯器完成一些特定的動作

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

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

  • 預處理器將忽略它不認識的 #pragma 指令
  • 不同的編譯器可能以不同的方式解釋同一條 #pragma 指令

一般用法:

#pragma parameter

注:不同的 parameter 參數語法和意義各不相同

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

下面為輸出結果:

三、#pragma once

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

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

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

下面為輸出結果,可以看到雖然在test.c 定義了兩次global.h,但是程序編譯沒有報錯,且能正常運行,這就是 #pragma once 作用的結果:

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

global.h:

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

四、#pragma pack

什么是內存對齊?

  • 不同類型的數據在內存中按照一定的規則排列
  • 而不一定是順序的一個接一個的排列

下面想想 Test1 和 Test2 所占的內存空間是否相同?

答案是否定的,Test1 占用 12 個字節,而 Test 占用 8 個字節

為什么需要內存對齊?

  • CPU對內存的讀取不是連續的,而是分成塊讀取的,塊的大小只能是1、2、4、8、16...字節
  • 當讀取操作的數據未對齊,則需要兩次總線周期來訪問內存,因此性能會大打折扣
  • 某些硬件平臺只能從規定的相對地址處讀取特定類型的數據,否則產生硬件異常

#pragma pack 用于指定內存對齊方式

#pragma pack 能夠改變編譯器的默認對齊方式

例如,下面代碼中,Test1 和 Test2 的內存均為 8 個字節

struct 占用的內存大小

第一個成員起始于 0 偏移處

每個成員按其類型大小和 pack 參數中較小的一個進行對齊

  • 偏移地址必須能被對齊參數整除
  • 結構體成員的大小取其內部長度最大的數據成員作為其大小

結構體總長度必須為所有對齊參數的整數倍

編譯器在默認情況下按照 4 字節對齊。

下面通過代碼,手工計算結構體所占用的內存大小

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

以 Test1 為例,c1 類型大小為 1 字節,而 pack 參數默認為 4,所以對齊參數取最小為 1;同理 s 的對齊參數為 2,偏移地址要被 2 整除,所以為 2;同理 c 的對齊參數為 1,偏移地址為 4;同理,i 的對齊參數為 4,因為偏移地址要能被 對齊參數 4 整除,在偏移地址 4 之后能被 4 整除的最小偏移地址為 8,所以 i 的偏移地址為 8,而 i 占用 4 個字節,所以 Test1 結構體占用的總字節數為 12 字節,這就和上面的圖對應起來了。

下面再通過一個例子感受一下:

在 gcc 編譯器下,test.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            12             8
};
 
#pragma pack()
 
int main()
{
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
 
    return 0;
}
 

下面為輸出結果:

這里注意兩點:

1.結構體成員的大小取其內部長度最大的數據成員作為其大小,所以 S1 的內存大小為 4,而pack 參數默認為 8,所以對齊參數為 4

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

3.gcc 編譯器暫時不支持 8 字節對齊,默認按照 4 字節對齊,所以 S2 中的 e 的對齊參數為 4,故 S2 占用內存大小為 20 字節。(學習采用的為 ubuntu 10.10)

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

#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;       //8            16             8
};
 
#pragma pack()
 
int main()
{
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
 
    return 0;
}
 

結果:

五、小結

#pragma 用于指示編譯器完成一些特定的動作

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

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

原文鏈接:https://blog.csdn.net/weixin_43129713/article/details/123543235

欄目分類
最近更新