我刚刚注意到,在 C 中可以通过将它们放在用逗号分隔的圆括号中来运行函数。我想知道它是否等同于正常运行它们(没有外部圆括号,用分号分隔(以及这种语法或行为的来源(这是作为功能添加的,这是否有特殊名称,是否有想要的副作用,这是否实际使用等(。作为函数调用的一部分,我每天编写数千次这个序列,这很有趣,但我不记得曾经独立看过它。
例子.c
#include <stdio.h>
int main(int argc, char *argv[])
{
(printf("Hello "), printf("World!n"));
return 0;
}
非常感谢您提供您的知识,莫里茨
此语法或行为源自何处
看看逗号运算符。
printf("Hello ")
首先进行评估,但其结果被丢弃。
printf("World!n")
接下来求值,其返回值决定整个表达式的返回值
(printf("Hello "), printf("World!n"));
同时,你可以看到"Hello World!"打印到控制台上,这可以用一种不太复杂的方式完成:
printf("Hello World!n");
这有特殊的名字吗
我会使用逗号运算符将其称为分组语句。
有想要的副作用吗
当您想要创建序列点时,它可能很有用。
这是真的用过吗
例如,如果您尝试
int success = (printf("Hello "), printf("World!n"));
你无法真正知道第一printf
的成功.这是以多种方式使用逗号运算符的坏例子。
逗号运算符:(逗号运算符(
逗号运算符表达式的形式为
LHS , RHS
其中
lhs- 任何表达式rhs - 除另一个逗号运算符以外的任何表达式(换句话说,逗号运算符的关联性是从左到右(首先,计算左操作数 lhs 并丢弃其结果值。
然后,发生一个序列点,以便lhs的所有副作用都完成。
然后,计算右操作数 rhs,逗号运算符将其结果作为非左值返回。
代码 1:
#include <stdio.h>
int main()
{
int n;
n= (printf("Hello"),printf(", World!"));
printf("nn = %d",n);
return 0;
}
这里打印的返回值将n=(5,8);
因此,逗号运算符丢弃 5 和 8 将分配给 n。
代码 2(不带括号(:
#include <stdio.h>
int main()
{
int n;
n= printf("Hello"),printf(", World!");
printf("nn = %d",n);
return 0;
}
这里的第一个n =5,8
将被分配给 5,因为赋值运算符的优先级高于逗号,并且右侧 printf 返回将被丢弃
如果要同时获取 printf 返回值
#include <stdio.h>
int main()
{
int n,m;
n= printf("Hello"),m=printf(", World!");
printf("nn = %d,m = %d",n,m);
return 0;
}
这里n=5,m=8;
谢谢。
">我想知道这是否等同于正常运行它们......">
由于逗号分隔的子表达式和逗号分隔的表达式从左到右计算之间都有一个序列点,因此此方法与单独的语句 1 没有显着差异(当在您的示例中使用时(。
6.5.17 逗号运算符
2 逗号运算符的左操作数被计算为 void 表达式;它的计算值与右操作数的计算之间存在一个序列点。然后计算正确的操作数;结果有其类型和值。
来源:ISO/IEC 9899:2011 (C11(
附件C
1以下是 5.1.2.3 中描述的序列点:
。
在以下运算符的第一和第二操作数的求值之间:逻辑 AND &&(6.5.13(;逻辑 OR ||(6.5.14);逗号 , (6.5.17(.
资料来源:ISO/IEC 9899:2011 (C11(,附录C
这两种方法的汇编代码也是等效的:
逗号分隔的子表达式:
puts@plt:
jmp QWORD PTR [rip+0x2fe2] # 404018 <puts@GLIBC_2.2.5>
push 0x0
jmp 401020 <.plt>
printf@plt:
jmp QWORD PTR [rip+0x2fda] # 404020 <printf@GLIBC_2.2.5>
push 0x1
jmp 401020 <.plt>
_dl_relocate_static_pie:
repz ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax+0x0]
main:
push rbp
mov rbp,rsp
sub rsp,0x10
mov DWORD PTR [rbp-0x4],edi
mov QWORD PTR [rbp-0x10],rsi
mov edi,0x402004
mov eax,0x0
call 401040 <printf@plt>
mov edi,0x40200b
call 401030 <puts@plt>
mov eax,0x0
leave
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax+rax*1+0x0]
法典:
#include <stdio.h>
int main(int argc, char *argv[])
{
(printf("Hello "), printf("World!n"));
return 0;
}
单独的语句:
puts@plt:
jmp QWORD PTR [rip+0x2fe2] # 404018 <puts@GLIBC_2.2.5>
push 0x0
jmp 401020 <.plt>
printf@plt:
jmp QWORD PTR [rip+0x2fda] # 404020 <printf@GLIBC_2.2.5>
push 0x1
jmp 401020 <.plt>
_dl_relocate_static_pie:
repz ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax+0x0]
main:
push rbp
mov rbp,rsp
sub rsp,0x10
mov DWORD PTR [rbp-0x4],edi
mov QWORD PTR [rbp-0x10],rsi
mov edi,0x402004
mov eax,0x0
call 401040 <printf@plt>
mov edi,0x40200b
call 401030 <puts@plt>
mov eax,0x0
leave
ret
nop WORD PTR cs:[rax+rax*1+0x0]
nop DWORD PTR [rax+rax*1+0x0]
法典:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello ");
printf("World!n");
return 0;
}