名稱空間
變體
操作

實現定義的行為控制

來自 cppreference.com
 
 
C++ 語言
 
 

實現定義的行為由 #pragma 指令控制。

目錄

[編輯] 語法

#pragma pragma-params (1)
_Pragma( string-literal ) (2) (C++11 起)
1) 以實現定義的方式行為。
2)string-literal 中移除 L 字首(如果有)、外層引號以及開頭/結尾的空白字元,將每個 \" 替換為 ",將每個 \\ 替換為 \,然後對結果進行詞法分析(如 翻譯階段 3),然後將結果用作 (1)#pragma 的輸入。

[編輯] 解釋

Pragma 指令控制編譯器實現特定的行為,例如停用編譯器警告或更改對齊要求。任何未識別的 pragma 都會被忽略。

[編輯] 非標準 pragmas

ISO C++ 語言標準不要求編譯器支援任何 pragmas。然而,多個實現支援一些非標準 pragmas

[編輯] #pragma STDC

ISO C 語言標準要求 C 編譯器支援以下三個 pragmas,一些 C++ 編譯器廠商在其 C++ 前端中不同程度地支援它們

#pragma STDC FENV_ACCESS arg (1)
#pragma STDC FP_CONTRACT arg (2)
#pragma STDC CX_LIMITED_RANGE arg (3)

其中 argONOFFDEFAULT

1) 如果設定為 ON,則通知編譯器程式將訪問或修改 浮點環境,這意味著禁止可能顛覆標誌測試和模式更改的最佳化(例如,全域性公共子表示式消除、程式碼移動和常量摺疊)。預設值是實現定義的,通常是 OFF
2) 允許浮點表示式的*收縮*,即省略舍入誤差和浮點異常的最佳化,這些誤差和異常在表示式按原樣求值時是可見的。例如,允許使用單個融合乘加 CPU 指令實現 (x * y) + z。預設值是實現定義的,通常是 ON
3) 通知編譯器複數的乘法、除法和絕對值可以使用簡化的數學公式 (x+iy)×(u+iv) = (xu-yv)+i(yu+xv)(x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2
+v2
)
|x+iy| = x2
+y2
,儘管可能存在中間溢位。換句話說,程式設計師保證將傳遞給這些函式的值範圍是有限的。預設值是 OFF

如果上述三個 pragmas 中的任何一個出現在所有外部宣告之外或複合語句內所有顯式宣告和語句之前的任何上下文中,則程式的行為是未定義的。

注意:不支援這些 pragmas 的編譯器可能會提供等效的編譯時選項,例如 gcc 的 -fcx-limited-range-ffp-contract

[編輯] #pragma once

#pragma once 是一個非標準 pragma,受到絕大多數現代編譯器的支援。如果它出現在標頭檔案中,則表示它只會被解析一次,即使它在同一個原始檔中被(直接或間接)包含多次。

防止多次包含同一標頭檔案的標準方法是使用包含守衛

#ifndef LIBRARY_FILENAME_H
#define LIBRARY_FILENAME_H
// contents of the header
#endif /* LIBRARY_FILENAME_H */

這樣,在任何翻譯單元中,除了第一次包含標頭檔案之外的所有包含都將從編譯中排除。所有現代編譯器都會記錄標頭檔案使用包含守衛的事實,並且只要守衛仍然被定義,如果再次遇到該檔案就不會重新解析它(參見例如 gcc)。

使用 #pragma once,相同的標頭檔案顯示為

#pragma once
// contents of the header

與標頭檔案守衛不同,此 pragma 使在多個檔案中錯誤地使用相同宏名稱成為不可能。另一方面,由於 #pragma once 是根據檔案系統級別的身份排除檔案的,因此如果標頭檔案在專案中存在於多個位置,則無法防止多次包含。

[編輯] #pragma pack

這一系列 pragmas 控制後續定義的類和聯合成員的最大對齊方式。

#pragma pack(arg) (1)
#pragma pack() (2)
#pragma pack(push) (3)
#pragma pack(push, arg) (4)
#pragma pack(pop) (5)

其中 arg 是一個小的二的冪,並以位元組為單位指定新的對齊方式。

1) 將當前對齊方式設定為值 arg
2) 將當前對齊方式設定為預設值(由命令列選項指定)。
3) 將當前對齊方式的值推入內部堆疊。
4) 將當前對齊方式的值推入內部堆疊,然後將當前對齊方式設定為值 arg
5) 從內部堆疊中彈出頂部條目,然後將(恢復)當前對齊方式設定為該值。

#pragma pack 可以減小類的對齊方式,但不能使類過度對齊。

另請參閱 GCCMSVC 的具體細節。

[編輯] 參考文獻

  • C++23 標準 (ISO/IEC 14882:2024)
  • 15.9 Pragma 指令 [cpp.pragma]
  • C++20 標準 (ISO/IEC 14882:2020)
  • 15.9 Pragma 指令 [cpp.pragma]
  • C++17 標準 (ISO/IEC 14882:2017)
  • 19.6 Pragma 指令 [cpp.pragma]
  • C++14 標準 (ISO/IEC 14882:2014)
  • 16.6 Pragma 指令 [cpp.pragma]
  • C++11 標準 (ISO/IEC 14882:2011)
  • 16.6 Pragma 指令 [cpp.pragma]
  • C++98 標準 (ISO/IEC 14882:1998)
  • 16.6 Pragma 指令 [cpp.pragma]

[編輯] 另請參閱

C 文件 關於 實現定義的行為控制

[編輯] 外部連結

1.  Visual Studio 中的 C++ pragmas
2.  GCC 接受的 Pragmas
3.  各個 pragma 描述IBM AIX XL C 16.1 中的標準 pragmas
4.  附錄 B. Pragmas 在 Sun Studio 11 C++ 使用者指南中
5.  Intel C++ 編譯器 pragmas
6.  HP aCC A.06.25 的釋出節點(包括 pragmas)