很多时候,在阅读时,我发现了这样的定义:
定义不是可执行语句。它们是编译器的消息。例如,定义
int i;
只是告诉编译器变量i的类型,并指示编译器保留空间 在内存中为变量。
像这样的陈述让我总是感到困惑,因为,恕我直言,一切都可以看作是"需要采取行动"。例如,在这种情况下,计算机必须执行一些操作来分配一些内存。
那些真正指的是哪些陈述?
答案 0 :(得分:4)
C语言识别本地声明和语句之间的相似性。这反映在
中6.8声明和阻止
3 一个块允许将一组声明和语句分组到一个语法单元中。具有自动存储持续时间的对象的初始化程序和具有块作用域的普通标识符的可变长度数组声明符将被评估,并且每次声明时,值都存储在对象中(包括在没有初始化程序的对象中存储不确定值)按执行顺序到达,好像是一个声明,并且在声明符出现的顺序中的每个声明中。
但是,正式地,声明不被归类为C语句。
请注意,本地声明的“statement-ish”属性实际上与初始化有关。至于内存分配......语言实际上并没有指定何时发生内存分配。当控制超过定义时,它不一定会发生。
外部定义绝对不是陈述,因为它们不参与控制流程。
答案 1 :(得分:1)
想象一下从汽车经销商那里买一辆新车。它们将向您显示前大灯的开关,齿轮的排列方式以及如何打开行李箱。这都是声明性的。什么都没发生。就编译器而言:不会创建任何输出。
一旦你开始使用汽车,你将根据你所获得的知识执行不同的行动。您将相应地换档并使用正确的开关打开前灯。就编译器而言:编译后的输出将根据事先给出的声明而变化。
答案 2 :(得分:1)
编译器将C语言转换为机器代码,可以由CPU执行。通常很容易看出哪些字节的机器代码与C代码中的哪些语句相对应。在显示C代码的运行方式时,调试器会使用此对应关系。
所以"声明的含义不是可执行的声明"是没有机器代码对应一个声明。这也意味着:
你可以在网上compiler explorer看到这个,它为C ++做了这个,但它足够接近C.它以不同的颜色描绘每行代码,以可视化哪些行产生哪个机器码。一个例子:
int square(int num) // painted in white
{ // painted in teal
int result; // painted in white
result = num * num; // painted in yellow
return result; // painted in gray
} // painted in red
square(int):
push rbp // painted in green
mov rbp, rsp // painted in green
mov DWORD PTR [rbp-20], edi // painted in green
mov eax, DWORD PTR [rbp-20] // painted in yellow
imul eax, DWORD PTR [rbp-20] // painted in yellow
mov DWORD PTR [rbp-4], eax // painted in yellow
mov eax, DWORD PTR [rbp-4] // painted in gray
pop rbp // painted in red
ret // painted in red
您可以看到以白色绘制的线条(声明)"不生成代码"和"不是可执行语句"。
"不可执行"想法不是一个硬性规则;只是一个指导方针。某些情况下声明是"可执行的":
int x = 0; // a trivial calculation, but it will appear in machine code
int y = x * (x + 1); // a non-trivial calculation
int a[rand() % 10 + 1]; // possible without initialization too (suggested by by user AnT)
答案 3 :(得分:0)
在创造性的编程范例中,声明是对程序应该采取行动的内容和方式的描述,而声明是对程序使用<的工具的描述/ strong>即可。行int i
仅声明程序需要类型为(int)的对象,而行int i = 0
声明程序需要类型为(int)的对象,初始值为零。这些都不是陈述,即使两者都需要该计划采取行动。
你是对的,每行代码可能 (1)涉及程序的一些“执行”。但区别在于语言是什么,作为算法的描述,而不是如何在现实世界的机器中实现。
(1):任何声明或陈述都可以优化,例如
答案 4 :(得分:0)
int i;
或static int i;
i
的任何预留空间,并对其进行零初始化。这些分配通常与其他分配相关联,并在程序加载时一举完成。
int i
可能无效。如果您使用它,编译器将尝试将其用作CPU寄存器的别名。如果采用所有寄存器并且无法重用旧的寄存器变量,或者如果获取变量的地址,则编译器将需要将变量溢出到堆栈中。函数的所有堆栈变量通常在进入函数时被一次性分配,并且分配将通过递增(/递减)堆栈指针(在寄存器中,当你进入时隐藏)来完成。 C)。实质上,分配自动变量的CPU时间成本最多只是减去整数所需时间的一小部分。