Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 常数之间的算术运算_C_C Preprocessor_Compile Time Constant - Fatal编程技术网

C 常数之间的算术运算

C 常数之间的算术运算,c,c-preprocessor,compile-time-constant,C,C Preprocessor,Compile Time Constant,考虑这一准则 #define A 5 #define B 3 int difference = A - B; “difference”的值是在编译时硬编码为“2”,还是在运行时计算出来的?标准没有规定这类内容。它没有提到像这样的潜在优化(这是有充分理由的。标准定义语义,而不是实现) 为什么不看看编译器的反汇编呢?这将给你一个明确的答案 那我们就这么做吧 以下是VC++10的输出: #include <iostream> #define A 5 #define B 3 int

考虑这一准则

#define A 5
#define B 3

int difference = A - B;

“difference”的值是在编译时硬编码为“2”,还是在运行时计算出来的?

标准没有规定这类内容。它没有提到像这样的潜在优化(这是有充分理由的。标准定义语义,而不是实现)

为什么不看看编译器的反汇编呢?这将给你一个明确的答案

那我们就这么做吧

以下是VC++10的输出:

#include <iostream>

#define A 5
#define B 3

int main() {
    int x = A - B;
    std::cout << x;  // make sure the compiler doesn't toss it away
010A1000  mov         ecx,dword ptr [__imp_std::cout (10A2048h)]  
010A1006  push        2  
010A1008  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]  
    return 0;
010A100E  xor         eax,eax  
#包括
#定义一个5
#定义B3
int main(){
int x=A-B;

std::cout宏
A
B
有点分散注意力。这是:

#define A 5
#define B 3

int difference = A - B;
与此完全相同:

int difference = 5 - 3;
那么让我们来讨论后者

5-3
是一个常量表达式,它是一个“可以在翻译过程中而不是运行时进行计算,因此可以在常量可能存在的任何位置使用”的表达式。它也是一个*整型常量表达式。例如,案例标签必须是整型常量表达式,因此您可以编写以下内容之一:

switch (foo) {
    case 2: /* this is a constant */
    ...
}
或者这个:

switch (foo) {
    case 5 - 3: /* this is a constant expression */
    ...
}
但请注意,该定义指出,它可以在翻译过程中进行计算,而不是必须进行计算。有些上下文需要常量表达式,在这些上下文中,表达式必须在编译时进行计算

但是假设
difference
是在某个函数中声明的,则初始值设定项不是这些上下文之一

任何值得你付出代价的编译器(即使是免费的)将在编译时将
5-3
减少到
2
,并生成将值
2
存储在
difference
中的代码。但不需要这样做。C标准指定了程序的行为;它没有指定必须如何实现该行为。但可以安全地假设,无论您使用什么编译器,都可以sing将用
2
替换
5-3

即使你写:

int difference = 2;
switch (foo) {
    case 5 - 3: /* ... */
    case 2:     /* ... */
}
编译器可以合法地生成代码,将值
5
加载到寄存器中,从中减去
3
,并将寄存器的内容存储到
差异
。这是一件愚蠢的事情,但语言标准并不排除它

只要最终结果是
difference
的值为
2
,语言标准就不关心它是如何实现的

另一方面,如果你写:

int difference = 2;
switch (foo) {
    case 5 - 3: /* ... */
    case 2:     /* ... */
}
然后,编译器必须计算结果,以便能够诊断错误(不能有两个大小写标签具有相同的值)

最后,如果在文件范围(在任何函数之外)定义
difference
,则初始值必须是常量。但在这种情况下,真正的区别不是编译时是否计算
5-3
,而是是否允许使用非常量表达式


参考:2011年C标准的最新草案是(大PDF);常量表达式在第6.6节中讨论。

您如何区分两者之间的差异?C标准有一个“仿佛”"规则,这意味着,如果你不能区分,实现可以随心所欲。分解代码,就是这样。我可能不会使用编译器,它不会降低到2,我认为它是不可行的,除非它是唯一的方法,以C的目标,一个平台本身是绝对可行的。我知道从第一公顷。nd体验到编译器的免费版本没有。你必须购买优化版本才能获得编译时常量计算这样基本的东西。当时我通过
enum
constant evaluation绕过了这个限制,但它对于任何规模的项目都是不可行的。检查由您的编译器将为您提供一个仅对该编译器具有决定性的答案(使用您使用的特定设置)@KeithThompson:任何像样的优化编译器都能做到这一点。我说过标准中没有规定,所以这显然适用于你的编译器。没错,我确实错过了C标记,但答案不会有任何不同。+1非常好,详细的答案。我考虑过深入研究……但后来我记得我在工作:D