【发布时间】:2014-04-14 03:27:49
【问题描述】:
代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
//what happens?
10*10;
//what happens?
printf("%d", 10*10);
return 0;
}
这两行在内存/编译中会发生什么。它被存储了吗? (10*10)
【问题讨论】:
代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
//what happens?
10*10;
//what happens?
printf("%d", 10*10);
return 0;
}
这两行在内存/编译中会发生什么。它被存储了吗? (10*10)
【问题讨论】:
声明
10*10;
没有效果。编译器可以选择根本不为此语句生成任何代码。另一方面,
printf("%d", 10*10);
将10*10 的结果传递给printf 函数,该函数将结果(100) 打印到标准输出。
【讨论】:
询问你的编译器!他们可能都会有一个有趣的答案。
这是gcc -c noop.c -o noop.o -g3 不得不说的(我通过objdump --disassemble --source 运行目标代码以产生下面的输出):
#include <stdio.h>
void test_code()
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
10*10;
//what happens?
printf("%d", 10*10);
4: b8 00 00 00 00 mov $0x0,%eax
9: be 64 00 00 00 mov $0x64,%esi
e: 48 89 c7 mov %rax,%rdi
11: b8 00 00 00 00 mov $0x0,%eax
16: e8 00 00 00 00 callq 1b <test_code+0x1b>
}
1b: 5d pop %rbp
1c: c3 retq
我的编译器将10*10 传递给printf 并在编译时将其相乘,然后将结果用作immediate($064,即十进制的 100)并将其放入寄存器中用于printf:
mov $0x64,%esi
省略了未分配给任何标识符的10*10 表达式。请注意,可能可能在某个地方找到某个编译器决定执行此计算并将其存储在寄存器中。
【讨论】:
在第一个问题中什么都没有,编译器将这样的表达式转换为值,并且由于您没有分配给变量它什么都不做,因此编译器将其删除。
在第二个中,值 100 被传递给 printf。
您必须注意,这取决于编译器要做什么,其中一些将被预先解析,而另一些将执行操作。
【讨论】:
10*10;
未存储。我的猜测是它应该给出编译器警告或错误。
printf("%d", 10*10);
应该打印:100。计算 (10*10) 的值(很可能由编译器计算,而不是在运行时),然后通过将值 (100) 压入堆栈来发送到 printf()。因此,该值将存储在堆栈中,直到 printf() 返回时恢复原始(pre-call-to-printf())堆栈帧。
【讨论】:
10*10;是完全有效的 C 语句,它不会给出任何错误。
10*10; 声明中没有错误,但是,它需要一个警告,例如“声明无效”。如果你把所有的警告都变成了错误,那么你会得到一个错误。但我同意它在语法上是正确的,你必须说服你的编译器告诉你编写这样的代码的错误。
在第一种情况下,由于该操作没有在任何地方使用,编译器可能会优化您的代码而不执行指令。
在第二种情况下,使用寄存器(堆栈)计算值并打印到控制台,而不是存储在其他任何地方。
【讨论】:
C 标准描述了程序在抽象机器上的作用。
但要真正确定实际发生的情况,您需要始终牢记一条规则:如果没有违反约束“好像”,编译器必须只输出具有可观察行为的代码说。
它被明确允许使用任何其他方式来实现它喜欢的结果。
这条规则通俗地称为“as-if”规则。
因此,您的程序等于例如:
#include <stdio.h>
int main(void) {
fputs("100", stdout);
}
或者
#include <stdio.h>
int main(void) {
putchar('1');
putchar('0');
putchar('0');
}
【讨论】: