其他運算子
不屬於任何其他主要類別的運算子集合。
| 本節尚不完整 原因:為此表及涵蓋多個主題的其他表格考慮一個更通用的目錄 |
| 運算子 | 運算子名稱 | 範例 | 描述 |
|---|---|---|---|
| (...) | 函數呼叫 | f(...) | 呼叫函式 f(),帶有零個或多個引數 |
| , | 逗號運算子 | a, b | 評估運算式 a,無視其傳回值並完成任何副作用,然後評估運算式 b,並傳回評估的類型與結果 |
| (type) | 類型轉換 | (type)a | 將 a 的類型轉換為 type |
| ? : | 條件運算子 | a ? b : c | 若 a 在邏輯上為真(其評估結果不為零),則評估運算式 b,否則評估運算式 c |
| sizeof | sizeof 運算子 | sizeof a | a 以位元組(bytes)為單位的長度 |
| _Alignof (自 C11 起) |
_Alignof 運算子 | _Alignof(type) | type 要求的對齊大小 |
| typeof | typeof 運算子 | typeof(a) | a 的類型 |
目錄 |
[編輯] 函式呼叫
函式呼叫運算式的形式為
expression ( argument-list (可選) ) |
|||||||||
其中
| expression | - | 任何指向函式類型的運算式(在 左值轉換 之後) |
| 引數列表 | - | 任何完整物件類型的運算式列表,以逗號分隔(此處不能是逗號運算子)。呼叫不接受引數的函式時可以省略。 |
函式呼叫運算式的行為取決於被呼叫函式的原型在呼叫點是否在作用域內。
[編輯] 呼叫具有原型的函式
...)。| (自 C99 起) |
void f(char* p, int x) {} int main(void) { f("abc", 3.14); // array to pointer and float to int conversions }
呼叫不具原型的函式1) 引數的評估順序是未指定的,且沒有順序關係。
2) 對每個引數運算式執行預設引數提升。
3) 執行賦值以將每個引數的值複製到對應的函式參數,忽略參數類型及其可能遞迴的元素或成員上的任何類型限定符。
4) 函式被執行,其傳回的值成為函式呼叫運算式的值(若函式傳回 void,則函式呼叫運算式是一個 void 運算式)
void f(); // no prototype int main(void) { f(1, 1.0f); // UB unless f is defined to take an int and a double } void f(int a, double c) {} 如果發生以下情況,對不具原型的函式進行呼叫的行為是未定義的:
|
(C23 之前) |
[編輯] 附註
指定要呼叫之函式的expression與所有引數的評估相對於彼此是無序的(但在函式體開始執行之前會有一個序列點)。
(*pf[f1()]) (f2(), f3() + f4()); // f1, f2, f3, f4 may be called in any order
儘管函式呼叫僅為指向函式的指標而定義,但由於函式向指標的隱式轉換,它也可以與函式指示符(designator)一起使用。
int f(void) { return 1; } int (*pf)(void) = f; int main(void) { f(); // convert f to pointer, then call (&f)(); // create a pointer to function, then call pf(); // call the function (*pf)(); // obtain the function designator, convert to pointer, then calls (****f)(); // convert to pointer, obtain the function, repeat 4x, then call (****pf)(); // also OK }
忽略未使用引數的函式(例如 printf)必須在作用域內具有原型(這類函式的原型必然使用末尾省略號參數)的情況下呼叫,以避免觸發未定義行為。
目前標準對準備函式參數語義的措辭有缺陷,因為它規定參數在呼叫時是從引數「賦值」的,這錯誤地拒絕了 const 限定的參數或成員類型,且不恰當地應用了 volatile 的語義(在許多平台上這對函式參數是無法實現的)。C11 之後的缺陷報告 DR427 提議將此類語義從「賦值」改為「初始化」,但以「非缺陷」結案。
|
若函式呼叫運算式中的 expression 完全由一個識別碼組成,且該識別碼未經宣告,則其行為如同該識別碼宣告為 extern int identifier(); // returns int and has no prototype 因此以下完整的程式在 C89 中是有效的 main() { int n = atoi("123"); // implicitly declares atoi as int atoi() } |
(直到 C99) |
[編輯] 逗號運算子
逗號運算子運算式的形式為
lhs , rhs |
|||||||||
其中
| lhs | - | 任何運算式 |
| rhs | - | 除了另一個逗號運算子以外的任何運算式(換句話說,逗號運算子的結合性是從左到右) |
首先,左運算元 lhs 會被評估,其結果值會被捨棄。
然後,發生一個序列點,使得 lhs 的所有副作用都已完成。
接著評估右運算元 rhs,其結果由逗號運算子作為非左值傳回。
[編輯] 附註
lhs 的類型可以是 void(也就是說,它可以是呼叫傳回 void 的函式,或者可以是轉型為 void 的運算式)
逗號運算子在 C++ 中可以是左值,但在 C 中永遠不是
逗號運算子可以傳回結構體(唯一其他傳回結構體的運算式是複合字面值、函式呼叫、賦值和條件運算子)
在以下語境中,逗號運算子不能出現在運算式的頂層,因為逗號有不同的含義
若必須在這些語境中使用逗號運算子,則必須將其括在括號內
// int n = 2,3; // error, comma assumed to begin the next declarator // int a[2] = {1,2,3}; // error: more initializers than elements int n = (2,3), a[2] = {(1,2),3}; // OK f(a, (t=3, t+2), c); // OK, first, stores 3 in t, then calls f with three arguments
頂層逗號運算子在陣列邊界中也是不允許的
// int a[2,3]; // error int a[(2,3)]; // OK, VLA array of size 3 (VLA because (2,3) is not a constant expression)
逗號運算子不允許出現在常數運算式中,無論它是否在頂層
// static int n = (1,2); // Error: constant expression cannot call the comma operator[編輯] 轉型運算子
參見 轉型運算子
[編輯] 條件運算子
條件運算子運算式的形式為
condition ? expression-true : expression-false |
|||||||||
其中
| 條件 (condition) | - | 純量類型的運算式 |
| 真值運算式 (expression-true) | - | 若條件比較不等於零時將被評估的運算式 |
| 假值運算式 (expression-false) | - | 若條件比較等於零時將被評估的運算式 |
僅允許以下運算式作為 expression-true 和 expression-false
|
(C23 起) |
| (C23 起) |
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) // if x is an Integer Constant Expression then macro expands to sizeof(*(1 ? NULL : (int *) 1)) // (void *)((x)*0l)) -> NULL // according to point (4) this further converts into sizeof(int) // if x is not an Integer Constant Expression then macro expands to // according to point (6) (sizeof(*(void *)(x)) // Error due incomplete type
[編輯] 附註
條件運算子永遠不是左值運算式,儘管它可能傳回結構體/聯合體類型的物件。唯一其他可以傳回結構體的運算式是 賦值、逗號、函式呼叫和 複合字面值。
注意在 C++ 中,它可能是左值運算式。
關於此運算子與賦值的相對優先順序詳情,請參見運算子優先順序。
條件運算子具有從右到左的結合性,這允許鏈式呼叫
#include <assert.h> enum vehicle { bus, airplane, train, car, horse, feet }; enum vehicle choose(char arg) { return arg == 'B' ? bus : arg == 'A' ? airplane : arg == 'T' ? train : arg == 'C' ? car : arg == 'H' ? horse : feet ; } int main(void) { assert(choose('H') == horse && choose('F') == feet); }
[編輯] sizeof 運算子
參見 sizeof 運算子
[編輯] _Alignof 運算子
參見 _Alignof 運算子
[編輯] typeof 運算子
參見 typeof 運算子
[編輯] 參考文獻
- C23 標準 (ISO/IEC 9899:2024)
- 6.5.2.2 函式呼叫 (p: TBD)
- 6.5.3.4 sizeof 與 _Alignof 運算子 (p: TBD)
- 6.5.4 轉型運算子 (p: TBD)
- 6.5.15 條件運算子 (p: TBD)
- 6.5.17 逗號運算子 (p: TBD)
- 6.7.3.5 Typeof 指定符 (p: 115-118)
- C17 標準 (ISO/IEC 9899:2018)
- 6.5.2.2 函式呼叫 (p: 58-59)
- 6.5.3.4 sizeof 與 _Alignof 運算子 (p: 64-65)
- 6.5.4 轉型運算子 (p: 65-66)
- 6.5.15 條件運算子 (p: 71-72)
- 6.5.17 逗號運算子 (p: 75)
- C11 標準 (ISO/IEC 9899:2011)
- 6.5.2.2 函式呼叫 (p: 81-82)
- 6.5.3.4 sizeof 與 _Alignof 運算子 (p: 90-91)
- 6.5.4 轉型運算子 (p: 91)
- 6.5.15 條件運算子 (p: 100)
- 6.5.17 逗號運算子 (p: 105)
- C99 標準 (ISO/IEC 9899:1999)
- 6.5.2.2 函式呼叫 (p: 71-72)
- 6.5.3.4 sizeof 運算子 (p: 80-81)
- 6.5.4 轉型運算子 (p: 81)
- 6.5.15 條件運算子 (p: 90-91)
- 6.5.17 逗號運算子 (p: 94)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.3.2.2 函式呼叫
- 3.3.3.4 sizeof 運算子
- 3.3.4 轉型運算子
- 3.3.15 條件運算子
- 3.3.17 逗號運算子
[編輯] 參閱
| 常用運算子 | ||||||
|---|---|---|---|---|---|---|
| 賦值 | 遞增 遞減 |
算術 | 邏輯 | 比較 | 成員 存取 |
其他 |
|
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
| C++ 文件 關於 其他運算子
|