Other operators
其他操作符
不符合任何其他主要类别的运营商的集合。
操作者 | 运营商名称 | 例 | 描述 |
---|---|---|---|
(...) | 函数调用 | F(...) | 使用零个或多个参数调用函数f() |
, | 逗号运算符 | a,b | 评估表达式a,忽视其返回值并完成任何副作用,然后评估表达式b,返回此评估的类型和结果 |
(类型) | 类型转换 | (类型)的 | 将类型转换为类型 |
? : | 条件运算符 | 一个 ?b:c | 如果a在逻辑上为真(不评估为零),则评估表达式b,否则评估表达式c |
的sizeof | 规模经营者 | sizeof a | 一个字节的大小 |
_Alignof(自C11以来) | _Alignof运营商 | _Alignof(类型) | 类型所需的对齐 |
函数调用
函数调用表达式具有表单。
expression ( argument-list(optional) ) | | |
---|
其中
表达 | - | 指针函数类型的任何表达式(在左值转换之后) |
---|---|---|
参数列表 | - | 任何完整对象类型的逗号分隔的表达式列表(不能是逗号运算符)。调用不带参数的函数时可能会被省略。 |
函数调用表达式的行为取决于被调用函数的原型是否在调用点范围内。
用原型调用函数
1)参数的数量必须等于参数的数量(除非使用省略号参数)。
2)每个参数的类型都必须是一种类型,以便隐式转换,就像通过赋值存在将相应参数的非限定类型转换为参数类型一样。
此外,对于在and之间使用关键字static的数组类型的每个参数,参数表达式都必须指定一个指向数组元素的指针,该数组元素至少具有参数大小表达式中指定的许多元素。 | (自C99以来) |
---|
3)参数以未指定的顺序进行评估,无需排序。
4)赋值(直到C11)执行初始化(从C11开始),将每个参数的值复制到相应的函数参数(注意;该函数可以修改其参数,并且这些更改不会影响参数; C函数调用只是调用 - 值)。
- 如果存在尾部省略号参数,则对剩余参数执行默认参数提升,这些参数可用
va_list
。
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)赋值(直到C11)执行初始化(从C11开始),将每个自变量的值复制到相应的函数参数中。
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) {}
没有原型的函数调用函数的行为是未定义的。
- 参数的数量与参数的数量不匹配。
注意
指定要调用的函数的表达式的评估和所有参数相对于彼此是不相关的(但是在函数的主体开始执行之前有一个序列点)。
(*pf[f1()]) (f2(), f3() + f4() // f1, f2, f3, f4 may be called in any order
尽管函数调用只是为指向函数的指针定义的,但由于函数到指针的隐式转换,它可以与函数指示符一起工作。
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
,)必须在范围内使用原型调用(此类函数的原型必须使用尾部省略号参数)以避免调用未定义的行为。
C11之后的缺陷报告DR 427在调用具有原型的函数时,为了允许const限定类型的参数(事实上
允许),从赋值到初始化相应的参数,改变了准备函数参数的语义。允许的隐式转换保留隐式转换,就像通过赋值一样,因为这是初始化也使用的。
一个函数调用表达式,其中表达式完全由一个标识符组成,并且该标识符未声明,就像标识符被声明为一样。extern int identifier(); //返回int并且没有原型所以下面的完整程序是有效的C89:main(){int n = atoi(“123”); //隐式声明atoi为int atoi()} | (直到C99) |
---|
Comma operator
逗号运算符表达式具有表单。
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 declarators 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
Cast operator
请参阅 cast 操作。
有条件的运算符
条件运算符表达式具有该形式。
condition ? expression-true : expression-false | | |
---|
其中
condition | - | an expression of scalar type |
---|---|---|
expression-true | - | the expression that will be evaluated if condition compares unequal to zero |
expression-false | - | the expression that will be evaluated if condition compares equal to zero |
只有以下表达式被允许为expression-true和expression-false。
- 任何算术类型的两个表达式
1)首先,评估状况。评估后有一个顺序点。
2)如果条件的结果不等于零,则执行表达式真,否则执行异常错误
3)执行从评估结果到通用类型的转换
,定义如下:
1)如果表达式具有算术类型,则通用类型是常规算术转换后的类型
2)如果表达式具有struct / union类型,则通用类型是该结构/联合类型
3)如果表达式都是无效的,整个条件运算符表达式就是一个void表达式
4)如果一个是指针而另一个是空指针常量,则该类型是该指针的类型
5)如果两者都是指针,则结果是指向组合指向类型的cvr限定符的类型的指针(即,如果一个是const int*
另一个volatile int*
,则结果是const volatile int*
),并且如果类型不同,指向类型是复合类型。
6)如果一个指向void的指针,则结果是一个指向无效且具有组合的cvr限定符的指针
注意
条件运算符永远不是左值表达式,尽管它可能会返回struct / union类型的对象。唯一可能返回stucts的其他表达式是赋值,逗号,函数调用和复合文字。
请注意,在C ++中,它可能是一个左值表达式。
有关此运算符和赋值的相对优先级的详细信息,请参阅运算符优先级。
条件运算符具有从右到左的关联性,这允许链接。
struct vehicle v = arg == 'B' ? bus :
arg == 'A' ? airplane :
arg == 'T' ? train :
arg == 'C' ? car :
arg == 'H' ? horse :
feet;
sizeof operator
请参阅sizeof运算符。
_Alignof operator
参见对齐操作符。