Namespaces
Variants

Other operators

From cppreference.net

不属于任何其他主要类别的运算符集合。

运算符 运算符名称 示例 描述
( ... ) 函数调用 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 - 由任意完整对象类型的表达式(不能是逗号运算符)组成的逗号分隔列表。调用无参数函数时可省略。

函数调用表达式的行为取决于被调用函数的原型是否在调用点处于 作用域 内。

调用带原型的函数

1) 形参数量必须与实参数量相等(除非使用省略号参数)。
2) 每个参数的类型必须满足:存在 如同通过赋值进行的隐式转换 ,能将对应实参的无限定类型转换为该参数的类型。
此外,对于每个在 [ ] 之间使用关键字 static 数组类型 参数,实参表达式必须指向一个数组元素,该数组至少包含形参大小表达式所指定数量的元素。
(since C99)
3) 参数的求值 以未指定顺序且无序列化关系 进行。
4) 赋值 操作将每个实参的值复制到对应的函数形参,忽略形参类型及其可能递归的元素或成员上的任何类型限定符(注意:函数可以修改其形参,且这些修改不会影响实参;C语言函数调用仅为传值调用)。
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前)

注释

用于指定被调用函数的 表达式 及所有实参的求值过程彼此间是 无顺序 的(但在函数体开始执行之前存在一个顺序点)

(*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)
  • 一个表达式是指针,另一个是空指针常量(例如 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
(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 + = 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
( type ) a
a ? b : c
sizeof


_Alignof
(自C11起)
(至C23止)

alignof
(自C23起)

C++ 文档 关于 其他运算符