眾所周知,實際引數的求值順序因一個 C 編譯器而異。但正如 ISO 9899:1999 在 §6.5.2.2.10 中所述:
該評價的順序功能標志,在實際引數和實際引數中的子運算式是不確定的,但實際呼叫之前的順序點。
自從我在 80 年代開始使用 C 以來,我從未遇到過生成代碼的編譯器,其中函式指示符在實際引數之后計算或與實際引數交錯。因此,在應用程式中使用以下(簡化的)代碼是否“安全”:
void* self;
(self = getPointerToObject())->classPtr->methodX(self);
或者真的有必要做這樣的事情:
void* self;
int (*methodPtr)(void*);
(methodPtr = (self = getPointerToObject())->classPtr->methodX, methodPtr(self));
在函式指示符和引數評估之間獲得一個明確的序列點(以一些性能代價)?
是否有 C 編譯器會生成代碼,其中第一個代碼被剪斷了不起作用(即向 methodX 提供一個未定義的 self 引數)?
uj5u.com熱心網友回復:
C99 定義了以下序列點:
- 在對引數求值后呼叫函式 (6.5.2.2)。
- 以下運算子的第一個運算元的結尾:邏輯與&&(6.5.13); 邏輯或 || (6.5.14);有條件的?(6.5.15);逗號,(6.5.17)。
- 一個完整的宣告符的結尾:declarators (6.7.5);
- 完整運算式的結尾:初始化程式(6.7.8);運算式陳述句中的運算式(6.8.3);選擇陳述句的控制運算式(if 或 switch)(6.8.4);while 或 do 陳述句的控制運算式 (6.8.5);for 陳述句的每個運算式(6.8.5.3);return 陳述句中的運算式 (6.8.6.4)。
- 在庫函式回傳之前(7.1.4)。
- 在與每個格式化輸入/輸出函式轉換說明符(7.19.6、7.24.2)相關聯的操作之后。
- 在每次呼叫比較函式之前和之后,以及在對比較函式的任何呼叫和作為引數傳遞給該呼叫的物件的任何移動之間(7.20.5)。
結論:不安全。它在您測驗時偶然作業的事實并不意味著所有編譯器都會這樣做。
uj5u.com熱心網友回復:
這與函式無關,而與括號有關。
int x = 5, y;
x = (y = x*x) * y;
這通過列印“有效” 625,但有一個序列點警告。像 OK 我會y先在括號中做,但這只是我。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/386840.html
下一篇:關于C中SIMD的說明
