//声明函数
void test(int a, int b);
int main() {
int a = 2;
test(a, a++);
return 0;
}
void test(int x, int y) {
printf("x=%d,y=%d", x, y);
}
//运行结果
x=3,y=2
想请教一下这个是为什么呢,明明给形参 y 传递的是自增的量,怎么就 x 变成 3,而 y 还是 2,
1
shylockhg 2018-12-04 17:19:14 +08:00
从右边传参数
|
3
misaka19000 2018-12-04 17:23:52 +08:00
在我电脑上面的运行结果
x=2,y=2 |
4
make 2018-12-04 17:24:03 +08:00 1
a++的返回值是自增之前的值,++a 的返回值才是自增之后的值
函数调用最后的参数先压栈 |
5
wutiantong 2018-12-04 17:26:08 +08:00 2
在 C++里这属于典型的 ub 了,因为函数传参时 eval 顺序是未定义的。
单就这个例子来说,先算了(a++) 后算了(a),结果没毛病。 |
6
shylockhg 2018-12-04 17:26:29 +08:00
这个很尴尬。。。
clang 3,2 gcc 2,2 |
8
kljsandjb 2018-12-04 17:29:06 +08:00 via iPhone 1
视 calling convention 而定吧
|
10
lovefantasy 2018-12-04 17:30:43 +08:00 via Android
等一个解释
|
11
KingHL 2018-12-04 17:31:26 +08:00 4
谁这么写代码,直接打死
|
13
WuwuGin 2018-12-04 17:35:15 +08:00 1
The language clearly says that certain things lead to undefined behavior. There is no problem, there is no "should" involved. If the undefined behavior changes when one of the involved variables is declared volatile, that doesn't prove or change anything. It is undefined; you cannot reason about the behavior.
https://stackoverflow.com/a/949443 https://en.wikipedia.org/wiki/Sequence_point 总结:在实际编程中,不应该出现这种二义性的行为。探讨此类问题没有实际意义。 |
14
des 2018-12-04 17:35:27 +08:00 via Android
不要这么写,这都什么鬼。顺手给你加一点好了
test(++a, a++) |
15
KingHL 2018-12-04 17:38:28 +08:00 2
参数入栈顺序从右向左,具体实现还要看不同的编译器行为,实际工程应用中,应该禁止这种不确定性的代码。如果是试题的话,估计是在考察你参数入栈顺序这个知识点。
|
16
xi2008wang 2018-12-04 17:38:48 +08:00
|
19
xjr1022 OP @misaka19000 试试 gcc 下编译,有惊喜
|
20
WordTian 2018-12-04 17:43:27 +08:00 via Android
看编译器用的什么调用约定。。。
就是参数是从左往右还是从右往左 |
23
misaka19000 2018-12-04 17:56:33 +08:00
用 gcc 取了下汇编,lea 指令那里看不太懂什么意思,有大佬能解释下吗
pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movl $2, -4(%rbp) movl -4(%rbp), %eax leal 1(%rax), %edx movl %edx, -4(%rbp) movl -4(%rbp), %edx movl %eax, %esi movl %edx, %edi call test movl $0, %eax |
24
freedomSky 2018-12-04 17:57:51 +08:00 via iPhone
我想知道这是哪儿的考研题
|
25
kljsandjb 2018-12-04 17:58:18 +08:00 via iPhone
@misaka19000 #23 lea 实现运算功能,自增 1
|
26
misaka19000 2018-12-04 17:59:09 +08:00
eax 存的应该是 2,但是不知道 edx 是咋算出来的。。。
|
27
kljsandjb 2018-12-04 17:59:17 +08:00 via iPhone
@misaka19000 #23 然后 edi 相当于第一个参数为 3,esi 为第二个参数为 2,结果就是楼主的结果
|
28
kljsandjb 2018-12-04 18:00:12 +08:00 via iPhone
@misaka19000 #26 这个代码没优化,讲的啰嗦、其实 edx 就是 lea1(%rax)算的
|
29
misaka19000 2018-12-04 18:00:23 +08:00
@kljsandjb #25 但是不清楚 rax 的值是多少额,lea 能知道是针对哪一个值进行自增吗
|
30
kljsandjb 2018-12-04 18:01:31 +08:00 via iPhone
@misaka19000 #29 rax 不是赋值了吗,先从栈取出来给它的
|
31
kljsandjb 2018-12-04 18:02:02 +08:00 via iPhone
@misaka19000 #29 lea 可以做最基本的运算,其实跟地址什么的没什么关系
|
32
XIVN1987 2018-12-04 18:02:29 +08:00
TDMGCC:x=3,y=2
|
33
kljsandjb 2018-12-04 18:03:47 +08:00 via iPhone
@misaka19000 #29 https://i.loli.net/2018/12/04/5c0650f7e4dae.png 这三行我觉得说得很清楚了呀~
|
34
misaka19000 2018-12-04 18:10:49 +08:00
|
35
kljsandjb 2018-12-04 18:11:33 +08:00 via iPhone
@misaka19000 #34 eax 是 rax 的低 32 位
|
36
kljsandjb 2018-12-04 18:11:48 +08:00 via iPhone
@misaka19000 #34 movl 操作会把高位清零
|
37
misaka19000 2018-12-04 18:14:51 +08:00
@kljsandjb #36 原来是这样啊,蟹蟹大佬(^ᗜ^)
|
38
Kaiv2 2018-12-04 18:22:09 +08:00 via Android
看看汇编,就很清晰了
|
39
GAMEKON 2018-12-04 18:25:27 +08:00 via Android
多写一行能死啊
|
40
sbw 2018-12-04 18:32:48 +08:00 2
ub,取决于编译器实现。
lea 用于寄存器的时候可以实现简单的 乘 2,乘 4,乘 5,加 1 这种计算,比 add 快(不需要进入 ALU )。 |
41
alaneuler 2018-12-04 19:06:48 +08:00
这就是 sequence point 吧。。。
https://en.wikipedia.org/wiki/Sequence_point |
42
alaneuler 2018-12-04 19:09:30 +08:00 1
Before a function is entered in a function call. The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.
|
43
transzero 2018-12-04 22:34:18 +08:00 via Android 1
默认 cdecl 调用方式,传参压栈从右往左,++是后计算的,所以第二个 2,第一个自然是 3
|
44
hx1997 2018-12-04 23:25:20 +08:00
国内考研题有的知识那叫一个老旧啊... 这种题也是上世纪谭浩强观念的遗毒,简直让人怀疑他们的知识体系从国外引进来就没有更新过,只会闭门造车......
|
45
iceheart 2018-12-14 10:27:06 +08:00 via Android
这是在写 bug 么?
|