C語言中#pragma的用法及使用解讀
一、比較矛盾的點(diǎn)-#pragma到底算不算關(guān)鍵字
有人認(rèn)為是算,而有人則認(rèn)為不算。
先看反對(duì)派,反對(duì)派認(rèn)為#pragma不算是C關(guān)鍵字的原因也很簡(jiǎn)單,即神并沒有認(rèn)可,那神是什么喃?即我們熟知的C89,C99,C11等協(xié)議。并沒有規(guī)定或者定義#pragma。
認(rèn)同派則認(rèn)為反對(duì)派過于迂腐,#pragma是個(gè)老伙伴了,它為c語言立過工,它為C語言流過血,就因?yàn)閰f(xié)議中沒有規(guī)定,就認(rèn)為他不是關(guān)鍵字,這樣很不好
二、閑話少說,看#pragma具體用法
pragma具體是指編譯器使用的,即這是編譯器能夠識(shí)別的和其他類型的#指令是一致的。我們最常見的#include和#define和undefine是一樣的。
2.1.#pragma的作用
#pragma 是 C/C++ 預(yù)處理指令之一,用來向編譯器傳遞一些平臺(tái)相關(guān)的編譯控制信息。
它的特點(diǎn)是:
- 編譯器相關(guān):不同編譯器支持的
#pragma指令不同 - 功能多樣:可以控制編譯器的警告、優(yōu)化、對(duì)齊方式、鏈接等
語法格式:
#pragma 指令名 [參數(shù)]
2.2. 常用的#pragma示例
(1)#pragma once—— 防止頭文件重復(fù)包含
#pragma once
- 作用:保證頭文件只被編譯一次
- 優(yōu)點(diǎn):比傳統(tǒng)的
#ifndef / #define / #endif更高效 - 缺點(diǎn):不是 C 標(biāo)準(zhǔn),但是大多數(shù)現(xiàn)代編譯器(GCC、Clang、MSVC)都支持
(2)#pragma pack—— 控制結(jié)構(gòu)體成員對(duì)齊方式
#pragma pack(push, 1) // 按1字節(jié)對(duì)齊,并保存當(dāng)前對(duì)齊狀態(tài)
struct Data {
char a;
int b;
short c;
};
#pragma pack(pop) // 恢復(fù)之前的對(duì)齊狀態(tài)- 用途:在網(wǎng)絡(luò)協(xié)議、文件格式、硬件驅(qū)動(dòng)等需要精確定義內(nèi)存布局的場(chǎng)景
#pragma pack(n)表示按 n 字節(jié)對(duì)齊(n 取 1、2、4、8 等)主要參數(shù)有push和pop和對(duì)齊的數(shù)字
(3)#pragma message—— 編譯時(shí)輸出提示信息
c運(yùn)行,這個(gè)就很簡(jiǎn)單,如果我們可以在代碼中的任何地方添加,這樣我們就能知道編譯到什么地方了
#pragma message("正在編譯 main.c...")
- 作用:在編譯過程中輸出自定義提示信息
- 常用于條件編譯檢查
(4)#pragma warning—— 控制編譯器警告
MSVC 編譯器:
#pragma warning(disable: 4996) // 禁用 4996 號(hào)警告 #pragma warning(once: 4820) // 僅顯示一次 4820 號(hào)警告 #pragma warning(error: 164) // 將 164 號(hào)警告視為錯(cuò)誤
GCC/Clang 一般用 -W、-Werror 等命令行參數(shù),不常用 #pragma warning
(5)#pragma comment—— 鏈接時(shí)加入庫或其他信息(MSVC)
#pragma comment(lib, "ws2_32.lib") // 鏈接 Winsock 庫 #pragma comment(linker, "/subsystem:windows") // 設(shè)置子系統(tǒng)類型
- 僅在 Windows + MSVC 環(huán)境有效
(6)#pragma GCC diagnostic—— GCC 特定的警告控制
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
int x; // 不會(huì)產(chǎn)生未使用變量警告
#pragma GCC diagnostic pop- 作用:臨時(shí)禁用 / 開啟某些 GCC 警告
2.3. 注意事項(xiàng)
- 可移植性差
#pragma是編譯器擴(kuò)展,不同編譯器支持的指令不同。例如#pragma once在 GCC/Clang/MSVC 可用,但在某些老編譯器可能不支持。 - 標(biāo)準(zhǔn)中未定義的
#pragma如果編譯器遇到不認(rèn)識(shí)的#pragma,會(huì)忽略該指令,不會(huì)報(bào)錯(cuò)。 - 盡量使用標(biāo)準(zhǔn)方法如果有標(biāo)準(zhǔn)方法(如
#ifndef代替#pragma once),優(yōu)先使用標(biāo)準(zhǔn)方法,提高可移植性。
總結(jié)
| #pragma 示例 | 作用 | 常見編譯器支持 |
|---|---|---|
| #pragma once | 防止頭文件重復(fù)包含 | GCC, Clang, MSVC |
| #pragma pack | 控制結(jié)構(gòu)體對(duì)齊 | 大多數(shù)編譯器 |
| #pragma message | 編譯時(shí)輸出信息 | 大多數(shù)編譯器 |
| #pragma warning | 控制警告 | MSVC |
| #pragma comment | 鏈接設(shè)置 | MSVC |
| #pragma GCC diagnostic | 控制 GCC 警告 | GCC, Clang |
? 結(jié)論:
#pragma是 C 語言中一個(gè)強(qiáng)大但平臺(tái)相關(guān)的預(yù)處理指令,可以用來控制編譯器行為、優(yōu)化、警告、對(duì)齊等。- 使用時(shí)要注意可移植性,優(yōu)先考慮標(biāo)準(zhǔn)方法,只在必要時(shí)使用特定編譯器的
#pragma擴(kuò)展。
三、一份不同編譯器支持的常用 #pragma 指令對(duì)照表
這樣在跨平臺(tái)開發(fā)時(shí)就能清楚哪些可用哪些不可用。
| 功能 | MSVC | GCC / Clang | Keil (ARMCC) | IAR | 說明 |
|---|---|---|---|---|---|
| 防止頭文件重復(fù)包含 | #pragma once | #pragma once | #pragma once | #pragma once | 非標(biāo)準(zhǔn),但現(xiàn)代編譯器普遍支持;標(biāo)準(zhǔn)做法是 #ifndef/#define/#endif |
| 結(jié)構(gòu)體 / 聯(lián)合對(duì)齊 | #pragma pack(push, n) #pragma pack(pop) | #pragma pack(push, n) #pragma pack(pop) | #pragma pack(push, n) #pragma pack(pop) | #pragma pack(push, n) #pragma pack(pop) | 設(shè)置結(jié)構(gòu)體成員對(duì)齊為 n 字節(jié);n 可取 1/2/4/8/16 |
| 編譯時(shí)消息輸出 | #pragma message("text") | #pragma message "text" | #pragma message("text") | #pragma message="text" | 在編譯輸出中顯示提示信息 |
| 禁用 / 開啟警告 | #pragma warning(disable: 1234) #pragma warning(default: 1234) | #pragma GCC diagnostic ignored "-Wxxx" | #pragma diag_suppress 1234 | #pragma diag_suppress=Pe123 | 臨時(shí)關(guān)閉 / 恢復(fù)特定警告 |
| 警告視為錯(cuò)誤 | #pragma warning(error: 1234) | #pragma GCC diagnostic error "-Wxxx" | #pragma diag_error 1234 | #pragma diag_error=Pe123 | 將指定警告當(dāng)作錯(cuò)誤處理 |
| 鏈接選項(xiàng) | #pragma comment(lib, "libname.lib")#pragma comment(linker, "/option") | 無(用 -l/-Wl,option) | 無(用 --library/ scatter file) | 無(用鏈接器選項(xiàng)) | 向鏈接器傳遞參數(shù)或添加庫 |
| 代碼段 / 節(jié)區(qū)控制 | #pragma section("name")__declspec(allocate("name")) | __attribute__((section("name"))) | __attribute__((section("name"))) | #pragma location="name" | 將變量 / 函數(shù)放入指定段 |
| 優(yōu)化控制 | #pragma optimize("", off)#pragma optimize("", on) | #pragma GCC push_options#pragma GCC optimize("O0")#pragma GCC pop_options | #pragma optimize=none | #pragma optimize=none | 局部關(guān)閉 / 開啟優(yōu)化 |
| 循環(huán)優(yōu)化 | #pragma loop(hint_parallel(n)) | #pragma GCC ivdep | 無 | 無 | 提示編譯器并行 / 向量化優(yōu)化 |
| 對(duì)齊控制 | __declspec(align(n)) | __attribute__((aligned(n))) | __attribute__((aligned(n))) | __attribute__((aligned(n))) | 指定變量 / 類型對(duì)齊 |
| 內(nèi)聯(lián)控制 | __forceinline__declspec(noinline) | __attribute__((always_inline))__attribute__((noinline)) | 同上 | 同上 | 強(qiáng)制內(nèi)聯(lián) / 禁止內(nèi)聯(lián) |
| 中斷函數(shù) | __declspec(naked) | 無(用 __attribute__((naked))) | __attribute__((naked)) | #pragma interrupt | 定義無棧幀 / 特殊中斷函數(shù) |
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用c++調(diào)用windows打印api進(jìn)行打印的示例代碼
這篇文章主要介紹了使用c++調(diào)用windows打印api進(jìn)行打印的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
C++函數(shù)重載與引用實(shí)戰(zhàn)案例詳解
在C++中允許多個(gè)函數(shù)同名,只要參數(shù)列表不同,借助函數(shù)重載,一個(gè)函數(shù)名可有多種用途,使命名更方便、調(diào)用更靈活,這篇文章主要介紹了C++函數(shù)重載與引用的相關(guān)資料,需要的朋友可以參考下2025-08-08
C++模板基礎(chǔ)之函數(shù)模板與類模板實(shí)例詳解
C++ 除了支持函數(shù)模板,還支持類模板(Class Template),所以下面這篇文章主要給大家介紹了關(guān)于C++模板基礎(chǔ)之函數(shù)模板與類模板的相關(guān)資料,需要的朋友可以參考下2021-06-06

