命名空間
變體
動作

其他運算子

出自 cppreference.com
< c‎ | 語言

不屬於任何其他主要類別的運算子集合。

運算子 運算子名稱 範例 描述
(...) 函數呼叫 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 - 任何指向函式類型的運算式(在 左值轉換 之後)
引數列表 - 任何完整物件類型的運算式列表,以逗號分隔(此處不能是逗號運算子)。呼叫不接受引數的函式時可以省略。

函式呼叫運算式的行為取決於被呼叫函式的原型在呼叫點是否在作用域內

[編輯] 呼叫具有原型的函式

1) 參數的數量必須等於引數的數量(除非使用了省略號參數 ...)。
2) 每個參數的類型必須滿足:存在一個如同賦值般的隱式轉換,能將對應引數的不限定類型轉換為參數的類型。
此外,對於每個在 [] 之間使用了 static 關鍵字的陣列類型參數,引數運算式必須指定一個指向陣列元素的指標,且該陣列至少要有參數長度運算式中指定的那麼多個元素。
(自 C99 起)
4) 執行賦值以將每個引數的值複製到對應的函式參數,並忽略參數類型(及其可能遞迴的元素或成員)上的任何類型限定符(注意:函式可以修改其參數,而這些變更不會影響引數;C 函式呼叫僅為值傳遞 call-by-value)。
5) 函式被執行,其傳回的值成為函式呼叫運算式的值(若函式傳回 void,則函式呼叫運算式是一個 void 運算式)
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) {}

如果發生以下情況,對不具原型的函式進行呼叫的行為是未定義的:

  • 引數數量與參數數量不匹配。
  • 引數提升後的類型與參數提升後的類型不相容,除非:
  • 相同整數類型的有號與無號版本被視為相容,前提是引數的值可以由這兩種類型表示。
  • 指向 void 的指標與指向(可能被 cvr 限定的)字元類型的指標被視為相容。
(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-trueexpression-false

  • 兩個皆為任何算術類型的運算式
  • 兩個皆為相同結構體聯合體類型的運算式
  • 兩個皆為 void 類型的運算式
  • 兩個皆為指標類型的運算式,指向相容的類型,忽略 cvr 限定符
(C23 起)
  • 一個是指標,另一個是空指標常數(例如 NULL或一個 nullptr_t(自 C23 起)
  • 一個是指向物件的指標,另一個是指向 void 的指標(可能被限定)
1) 首先,評估 condition。在此評估之後有一個序列點
2)condition 的結果不等於零,則執行 expression-true,否則執行 expression-false
3) 對評估結果執行轉換至「共同類型」,其定義如下
1) 若運算式為算術類型,共同類型是經過一般算術轉換後的類型
2) 若運算式為結構體/聯合體類型,共同類型就是該結構體/聯合體類型
3) 若兩個運算式皆為 void,則整個條件運算子運算式是一個 void 運算式
4) 若一個是指標而另一個是空指標常數nullptr_t(自 C23 起),其類型為該指標的類型
5) 若兩個都是指標,結果是指向「結合了兩個指向類型之 cvr 限定符」的類型的指標(也就是說,若一個是 const int* 另一個是 volatile int*,結果為 const volatile int*),且若類型不同,指向的類型則為合成類型
6) 若一個是 void 指標,結果是具有合併 cvr 限定符的 void 指標
7) 若兩個都是 nullptr_t 類型,共同類型也是 nullptr_t
(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 += b
a -= b
a *= b
a /= b
a %= b
a &&= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(型別) a
a ? b : c
sizeof


_Alignof
(自 C11 起)
(C23 之前)

alignof
(C23 起)

C++ 文件 關於 其他運算子
English Deutsch 日本語 中文(简体) 中文(繁體)