const 正确性是否为编译器提供了更多优化空间?

2021-12-13 00:00:00 pointers c constants const-correctness c++

我知道它提高了可读性并使程序不易出错,但它对性能的提高有多大?

I know that it improves readability and makes the program less error-prone, but how much does it improve the performance?

顺便提一下,引用和 const 指针之间的主要区别是什么?我会假设它们以不同的方式存储在内存中,但如何?

And on a side note, what's the major difference between a reference and a const pointer? I would assume they're stored in the memory differently, but how so?

推荐答案

声明常量指针或常量引用永远不会帮助任何编译器优化任何东西.(尽管请参阅此答案底部的更新.)

Declaring a pointer-to-const or reference-of-const never helps any compiler to optimize anything. (Although see the Update at the bottom of this answer.)

const 声明仅指示如何在其声明的范围内使用标识符;并不是说底层对象不能改变.

The const declaration only indicates how an identifier will be used within the scope of its declaration; it does not say that the underlying object can not change.

示例:

int foo(const int *p) {
    int x = *p;
    bar(x);
    x = *p;
    return x;
}

编译器不能假设 *p 没有被 bar() 的调用修改,因为 p 可能是(例如)指向全局 int 的指针,bar() 可能会修改它.

The compiler cannot assume that *p is not modified by the call to bar(), because p could be (e.g.) a pointer to a global int and bar() might modify it.

如果编译器足够了解foo()的调用者和bar()的内容,它可以证明bar()不修改*p,那么它也可以在没有 const 声明的情况下执行该证明.

If the compiler knows enough about the caller of foo() and the contents of bar() that it can prove bar() does not modify *p, then it can also perform that proof without the const declaration.

但总的来说,这是真的.因为const 只在声明的范围内起作用,编译器已经可以看到你在该范围内如何处理指针或引用;它已经知道您没有修改底层对象.

But this is true in general. Because const only has an effect within the scope of the declaration, the compiler can already see how you are treating the pointer or reference within that scope; it already knows that you are not modifying the underlying object.

所以简而言之,所有 const 在这个上下文中所做的就是防止你犯错误.它不会告诉编译器任何它不知道的东西,因此它与优化无关.

So in short, all const does in this context is prevent you from making mistakes. It does not tell the compiler anything it does not already know, and therefore it is irrelevant for optimization.

那些调用 foo() 的函数呢?喜欢:

What about functions that call foo()? Like:

int x = 37;
foo(&x);
printf("%d
", x);

由于foo() 接受一个const int *,所以编译器能证明这会打印37吗?

Can the compiler prove that this prints 37, since foo() takes a const int *?

没有.即使 foo() 接受一个指向常量的指针,它也可能会抛弃常量并修改 int.(这是不是未定义的行为.)这里再次重申,编译器一般不能做出任何假设;如果它对 foo() 有足够的了解来进行这样的优化,它就会知道即使没有 const.

No. Even though foo() takes a pointer-to-const, it might cast the const-ness away and modify the int. (This is not undefined behavior.) Here again, the compiler cannot make any assumptions in general; and if it knows enough about foo() to make such an optimization, it will know that even without the const.

const 可能允许优化的唯一时间是这样的情况:

The only time const might allow optimizations is cases like this:

const int x = 37;
foo(&x);
printf("%d
", x);

在这里,通过任何机制(例如,通过获取指向它的指针并丢弃 const)来修改 x 就是调用未定义行为.因此编译器可以自由地假设您不这样做,并且它可以将常量 37 传播到 printf() 中.这种优化对于您声明 const 的任何对象都是合法的.(实际上,您从不引用的局部变量不会受益,因为编译器已经可以看到您是否在其范围内修改了它.)

Here, to modify x through any mechanism whatsoever (e.g., by taking a pointer to it and casting away the const) is to invoke Undefined Behavior. So the compiler is free to assume you do not do that, and it can propagate the constant 37 into the printf(). This sort of optimization is legal for any object you declare const. (In practice, a local variable to which you never take a reference will not benefit, because the compiler can already see whether you modify it within its scope.)

要回答您的旁注"问题,(a) const 指针是一个指针;(b) const 指针可以等于 NULL.您是正确的,内部表示(即地址)很可能是相同的.

To answer your "side note" question, (a) a const pointer is a pointer; and (b) a const pointer can equal NULL. You are correct that the internal representation (i.e. an address) is most likely the same.

[更新]

正如 Christoph 在评论中指出的那样,我的回答是不完整的,因为它没有提到 restrict.

As Christoph points out in the comments, my answer is incomplete because it does not mention restrict.

C99 标准的第 6.7.3.1 (4) 节说:

Section 6.7.3.1 (4) of the C99 standard says:

在每次执行 B 期间,让 L 是任何基于 P 具有 &L 的左值.如果 L 用于访问它指定的对象 X 的值,并且 X 也被修改(以任何方式),那么以下要求适用: T 不应是 const 限定的....

During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T shall not be const-qualified. ...

(这里 B 是一个基本块,P,一个指向 T 的限制指针,在其作用域内.)

(Here B is a basic block over which P, a restrict-pointer-to-T, is in scope.)

因此,如果 C 函数 foo() 被声明如下:

So if a C function foo() is declared like this:

foo(const int * restrict p)

...那么编译器可能假设在p的生??命周期内不会对*p进行修改――即,在foo() 的执行――否则行为将是未定义的.

...then the compiler may assume that no modifications to *p occur during the lifetime of p -- i.e., during the execution of foo() -- because otherwise the Behavior would be Undefined.

因此,原则上,将 restrict 与指向常量的指针相结合可以实现上面忽略的两种优化.我想知道有没有编译器真的实现了这样的优化?(至少 GCC 4.5.2 没有.)

So in principle, combining restrict with a pointer-to-const could enable both of the optimizations that are dismissed above. Do any compilers actually implement such an optimization, I wonder? (GCC 4.5.2, at least, does not.)

请注意,restrict 仅存在于 C 中,而不存在于 C++(甚至 C++0x)中,除非作为特定于编译器的扩展.

Note that restrict only exists in C, not C++ (not even C++0x), except as a compiler-specific extension.

相关文章