Other operators
不属于任何其他主要类别的运算符集合。
|
本节内容尚不完整
原因:建议为此表及其他涵盖多主题的表格设计更通用的目录结构 |
| 运算符 | 运算符名称 | 示例 | 描述 |
|---|---|---|---|
| ( ... ) | 函数调用 | 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 所需的对齐要求 |
| typeof | typeof 运算符 | typeof ( a ) | a 的类型 |
目录 |
函数调用
函数调用表达式的形式为
表达式
(
参数列表
(可选)
)
|
|||||||||
其中
| expression | - | 任何指向函数类型的表达式(在 左值转换 之后) |
| argument-list | - | 由任意完整对象类型的表达式(不能是逗号运算符)组成的逗号分隔列表。调用无参数函数时可省略。 |
函数调用表达式的行为取决于被调用函数的原型是否在调用点处于 作用域 内。
调用带原型的函数
| (since 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前) |
注释
用于指定被调用函数的 表达式 及所有实参的求值过程彼此间是 无顺序 的(但在函数体开始执行之前存在一个顺序点)
(*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)(); // 同样有效 }
忽略未使用参数的函数,例如 printf ,必须在作用域内使用原型调用(此类函数的原型必须使用 尾随省略号 参数),以避免引发未定义行为。
当前标准中关于函数参数准备语义的措辞存在缺陷,因为它规定在调用时通过赋值方式将实参传递给形参,这错误地拒绝了常量限定参数或成员类型,并不恰当地应用了易变性语义——这种语义在许多平台上对函数参数而言是无法实现的。一份C11标准后的缺陷报告 DR427 曾提议将此类语义从赋值改为初始化,但最终以“非缺陷”结论关闭。
|
当函数调用表达式中的 表达式 完全由一个标识符组成且该标识符未声明时,其行为如同该标识符被声明为: 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}; // 正确 f(a, (t=3, t+2), c); // 正确:首先将3存入t,然后使用三个参数调用f
数组边界中也不允许使用顶层逗号运算符
// int a[2,3]; // 错误 int a[(2,3)]; // 正确,大小为3的VLA数组(因为(2,3)不是常量表达式所以是VLA)
逗号运算符不允许在 常量表达式 中使用,无论其是否处于顶层作用域
// static int n = (1,2); // 错误:常量表达式不能调用逗号运算符
强制转换运算符
参见 强制转换运算符
条件运算符
条件运算符表达式的形式为
条件
?
真值表达式
:
假值表达式
|
|||||||||
其中
| condition | - | 标量类型的表达式 |
| expression-true | - | 当 condition 与零比较不相等时将被求值的表达式 |
| expression-false | - | 当 condition 与零比较相等时将被求值的表达式 |
仅以下表达式可作为 expression-true 和 expression-false
|
(since C23) |
| (since 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++中,它可能是一个左值表达式。
请参阅 运算符优先级 了解此运算符与赋值运算符相对优先级的详细信息。
条件运算符具有从右到左的结合性,这使得链式操作成为可能
#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 函数调用 (页: 待定)
-
- 6.5.3.4 sizeof 和 _Alignof 运算符 (页: 待定)
-
- 6.5.4 强制类型转换运算符 (页: 待定)
-
- 6.5.15 条件运算符 (页: 待定)
-
- 6.5.17 逗号运算符 (页: 待定)
-
- 6.7.3.5 typeof 说明符 (页: 115-118)
- C17 标准 (ISO/IEC 9899:2018):
-
- 6.5.2.2 函数调用 (页码: 58-59)
-
- 6.5.3.4 sizeof 和 _Alignof 运算符 (页码: 64-65)
-
- 6.5.4 强制转换运算符 (页码: 65-66)
-
- 6.5.15 条件运算符 (页码: 71-72)
-
- 6.5.17 逗号运算符 (页码: 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 函数调用(页码:71-72)
-
- 6.5.3.4 sizeof运算符(页码:80-81)
-
- 6.5.4 强制类型转换运算符(页码:81)
-
- 6.5.15 条件运算符(页码:90-91)
-
- 6.5.17 逗号运算符(页码: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++ 文档
关于
其他运算符
|