其他运算符
不适合任何其他主要类别的运算符的汇集。
本节未完成 原因:为这个和其他表格考虑更通用的,覆盖多个专题的 ToC |
运算符 | 运算符名 | 示例 | 描述 |
---|---|---|---|
(...) | 函数调用 | f(...) | 以令或更多参数调用 f() |
, | 逗号运算符 | a, b | 求值表达式 a ,舍弃其返回值并完成任何副效应,然后求值表达式 b ,返回此求值的类型和结果 |
(type) | 转型 | (type)a | 转型 a 的类型为 type |
? : | 条件运算符 | a ? b : c | 若 a 逻辑上为真(不求值为零)则求值表达式 b ,否则求值表达式 c |
sizeof | sizeof 运算符 | sizeof a | a 的字节大小 |
_Alignof (C11 起) | _Alignof 运算符 | _Alignof(type) | type 对齐 |
函数调用
函数调用表达式拥有形式
表达式 ( 实参列表(可选) )
|
|||||||||
其中
表达式 | - | 任何指向函数指针类型表达式(在左值转换后) |
实参列表 | - | 任何完整对象类型表达式(不能是逗号运算符)的逗号分隔列表。调用不接受参数的函数时可以省略。 |
函数调用表达式的行为,取决于正在调用的函数的原型是否在调用点处于作用域中。
调用有原型函数
(C99 起) |
void f(char* p, int x) {} int main(void) { f("abc", 3.14); // 数组到指针和 float 到 int 转换 }
调用无原型函数1) 以未指定顺序无序地求值实参。
2) 在每个实参表达式上进行默认参数提升。
3) 进行赋值,复制每个实参到对应的函数形参,忽略形参类型及其可能为递归的元素或成员上的类型限定符,若存在。
4) 执行函数,而其所返回的值成为函数调用表达式的值(若函数返回 void ,则函数调用表达式为 void 表达式)
void f(); // 无原型 int main(void) { f(1, 1.0f); // UB ,除非定义 f 为接收一个 int 和一个 double } void f(int a, double c) {} 调用无原型函数的行为未定义,若
|
(C23 前) |
注解
指代要调用的函数的 表达式 和所有参数的求值相对于彼此无序(但在函数开始执行前有一个序列点)
(*pf[f1()]) (f2(), f3() + f4()); // 可以以任何顺序调用 f1 、 f2 、 f3 、 f4
尽管函数调用只对指向函数指针定义,它亦能作用于函数指代器,因为函数到指针隐式转换。
int f(void) { return 1; } int (*pf)(void) = f; int main(void) { f(); // 转换 f 为指针,然后调用 (&f)(); // 创建指向函数指针,然后调用 pf(); // 调用函数 (*pf)(); // 获得函数指代器,转换为指针,然后滴啊用、 (****f)(); // 转换为指针,获得函数,重复 4 次,然后调用 (****pf)(); // 亦 OK }
必须用在作用域中的原型调用忽略不使用实参的函数,如 printf (这种函数的原型需要使用尾随省略号形参),以避免未定义行为。
当前准备函数形参的语义的标准遣词是有缺陷的,因为它指定在调用时形参从实参赋值,这错误地拒绝了 const 限定的形参或成员类型,并且不恰当地应用了在许多平台上对于函数形参无法实现的 volatile 语义。 C11 后的缺陷报告 DR 427 提议将该语义从赋值改为初始化,但被作为非缺陷关闭。
其 表达式 完全由一个标识符组成,而未声明该标识符的函数调用表达式,表现为通过将该标识符声明如下 extern int identifier(); // 返回 int 且无原型 故下列完整程序在 C89 中合法: main() { int n = atoi("123"); // 隐式声明 atoi 为 int atoi() } |
(C99 前) |
逗号运算符
逗号运算符表达式拥有形式
lhs , rhs
|
|||||||||
其中
lhs | - | 任何表达式 |
rhs | - | 任何异于另一逗号运算符的表达式(换言之,逗号运算符的结合性为从左到右) |
首先,求值左运算数 lhs 并舍弃其结果值。
然后,发生序列点,从而 lhs 的所有副效应完成。
然后,求值右运算数 rhs ,而逗号运算符作为非左值返回其结果。
注意
lhs 的类型可为 void (即可为对返回 void 的函数的调用,或能为 转型到 void 的表达式)。
逗号运算符在 C++ 中可为左值,但 C 中决不是。
逗号运算符可返回结构体(其他返回结构体的表达式仅有复合字面量、函数调用、赋值和条件运算符)。
下列语境中,逗号运算符不能出现于表达式的顶层,因为逗号有不同含义:
若必须在这种语境中使用逗号运算符,则必须加括号:
// int n = 2,3; // 错误:认为逗号开始下个声明器 // int a[2] = {1,2,3}; // 错误:初始化器多于元素 int n = (2,3), a[2] = {(1,2),3}; // OK f(a, (t=3, t+2), c); // OK :存储 3 于 t ,然后以三个参数调用 f
数组边界中亦禁止顶层逗号
// int a[2,3]; // 错误 int a[(2,3)]; // OK :大小为 3 的 VLA 数组(因为 (2, 3) 不是常量表达式故为 VLA )
常量表达式中不允许逗号,不管它是否出现于顶层
// static int n = (1,2); // 错误:常量表达式不能调用逗号运算符
转型运算符
条件运算符
条件运算符表达式拥有形式
条件 ? 表达式真 : 表达式假
|
|||||||||
其中
条件 | - | 标量类型表达式 |
表达式真 | - | 若条件比较不等于零则将求值的表达式 |
表达式假 | - | 若条件比较等于零则将求值的表达式 |
仅允许下列表达式为 表达式真 和 表达式假
|
(C23 起) |
(C23 起) |
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) // 若 x 是整数常量表达式,则宏展开成 sizeof( 1 ? NULL : (int *) 1) // (void *)((x)*0l)) -> NULL // 按照第 (4) 点这进一步转换成 sizeof(int) // 若 x 不是整数常量表达式,则宏按照第 (6) 点展开成 (sizeof(*(void *)(x)) // 因不完整类型而错误
注解
条件运算符决不是左值表达式,尽管它可以返回结构体/联合体类型的对象。其他可以返回结构体的表达式仅有赋值、逗号、函数调用和复合字面量。
注意 C++ 中它可以为左值表达式。
此运算符和赋值的相对优先级上的细节见运算符优先级。
条件运算符拥有从右到左结合性,这允许链式写法
struct vehicle v = arg == 'B' ? bus : arg == 'A' ? airplane : arg == 'T' ? train : arg == 'C' ? car : arg == 'H' ? horse : feet;
sizeof 运算符
_Alignof 运算符
引用
- C17 标准(ISO/IEC 9899:2018):
- 6.5.2.2 Function calls (第 58-59 页)
- 6.5.3.4 The sizeof and _Alignof operators (第 64-65 页)
- 6.5.4 Cast operators (第 65-66 页)
- 6.5.15 Conditional operator (第 71-72 页)
- 6.5.17 Comma operator (第 75 页)
- C11 标准(ISO/IEC 9899:2011):
- 6.5.2.2 Function calls (第 81-82 页)
- 6.5.3.4 The sizeof and _Alignof operators (第 90-91 页)
- 6.5.4 Cast operators (第 91 页)
- 6.5.15 Conditional operator (第 100 页)
- 6.5.17 Comma operator (第 105 页)
- C99 标准(ISO/IEC 9899:1999):
- 6.5.2.2 Function calls (第 71-72 页)
- 6.5.3.4 The sizeof operator (第 80-81 页)
- 6.5.4 Cast operators (第 81 页)
- 6.5.15 Conditional operator (第 90-91 页)
- 6.5.17 Comma operator (第 94 页)
- C89/C90 标准(ISO/IEC 9899:1990):
- 3.3.2.2 Function calls
- 3.3.3.4 The sizeof operator
- 3.3.4 Cast operators
- 3.3.15 Conditional operator
- 3.3.17 Comma operator
参阅
常用运算符 | ||||||
---|---|---|---|---|---|---|
赋值 | 自增 自减 |
算术 | 逻辑 | 比较 | 成员 访问 |
其他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |