//声明函数
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,
//声明函数
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,
|
shylockhgDec 4, 2018
1
从右边传参数
|
|
misaka19000Dec 4, 2018
3
在我电脑上面的运行结果
x=2,y=2 |
|
4
a++的返回值是自增之前的值,++a 的返回值才是自增之后的值
函数调用最后的参数先压栈 |
|
5
在 C++里这属于典型的 ub 了,因为函数传参时 eval 顺序是未定义的。
单就这个例子来说,先算了(a++) 后算了(a),结果没毛病。 |
|
shylockhgDec 4, 2018
6
这个很尴尬。。。
clang 3,2 gcc 2,2 |
|
8
视 calling convention 而定吧
|
|
lovefantasyDec 4, 2018 via Android
10
等一个解释
|
|
11
谁这么写代码,直接打死
|
|
13
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 总结:在实际编程中,不应该出现这种二义性的行为。探讨此类问题没有实际意义。 |
|
desDec 4, 2018 via Android
14
不要这么写,这都什么鬼。顺手给你加一点好了
test(++a, a++) |
|
15
参数入栈顺序从右向左,具体实现还要看不同的编译器行为,实际工程应用中,应该禁止这种不确定性的代码。如果是试题的话,估计是在考察你参数入栈顺序这个知识点。
|
|
19
@misaka19000 试试 gcc 下编译,有惊喜
|
|
WordTianDec 4, 2018 via Android
20
看编译器用的什么调用约定。。。
就是参数是从左往右还是从右往左 |
|
misaka19000Dec 4, 2018
23
用 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 |
|
freedomSkyDec 4, 2018 via iPhone
24
我想知道这是哪儿的考研题
|
|
kljsandjbDec 4, 2018 via iPhone
25
@misaka19000 #23 lea 实现运算功能,自增 1
|
|
misaka19000Dec 4, 2018
26
eax 存的应该是 2,但是不知道 edx 是咋算出来的。。。
|
|
kljsandjbDec 4, 2018 via iPhone
27
@misaka19000 #23 然后 edi 相当于第一个参数为 3,esi 为第二个参数为 2,结果就是楼主的结果
|
|
kljsandjbDec 4, 2018 via iPhone
28
@misaka19000 #26 这个代码没优化,讲的啰嗦、其实 edx 就是 lea1(%rax)算的
|
|
misaka19000Dec 4, 2018
29
@kljsandjb #25 但是不清楚 rax 的值是多少额,lea 能知道是针对哪一个值进行自增吗
|
|
kljsandjbDec 4, 2018 via iPhone
30
@misaka19000 #29 rax 不是赋值了吗,先从栈取出来给它的
|
|
kljsandjbDec 4, 2018 via iPhone
31
@misaka19000 #29 lea 可以做最基本的运算,其实跟地址什么的没什么关系
|
|
XIVN1987Dec 4, 2018
32
TDMGCC:x=3,y=2
|
|
kljsandjbDec 4, 2018 via iPhone
33
@misaka19000 #29 https://i.loli.net/2018/12/04/5c0650f7e4dae.png 这三行我觉得说得很清楚了呀~
|
|
misaka19000Dec 4, 2018
34
|
|
kljsandjbDec 4, 2018 via iPhone
35
@misaka19000 #34 eax 是 rax 的低 32 位
|
|
kljsandjbDec 4, 2018 via iPhone
36
@misaka19000 #34 movl 操作会把高位清零
|
|
misaka19000Dec 4, 2018
37
@kljsandjb #36 原来是这样啊,蟹蟹大佬(^ᗜ^)
|
|
Kaiv2Dec 4, 2018 via Android
38
看看汇编,就很清晰了
|
|
GAMEKONDec 4, 2018 via Android
39
多写一行能死啊
|
|
40
ub,取决于编译器实现。
lea 用于寄存器的时候可以实现简单的 乘 2,乘 4,乘 5,加 1 这种计算,比 add 快(不需要进入 ALU )。 |
|
alaneulerDec 4, 2018
41
这就是 sequence point 吧。。。
https://en.wikipedia.org/wiki/Sequence_point |
|
42
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
默认 cdecl 调用方式,传参压栈从右往左,++是后计算的,所以第二个 2,第一个自然是 3
|
|
hx1997Dec 4, 2018
44
国内考研题有的知识那叫一个老旧啊... 这种题也是上世纪谭浩强观念的遗毒,简直让人怀疑他们的知识体系从国外引进来就没有更新过,只会闭门造车......
|
|
iceheartDec 14, 2018 via Android
45
这是在写 bug 么?
|