const-correctness 是否给编译器更多的优化空间?

2022-01-23 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?

推荐答案

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

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);

编译器能否证明这打印出 37,因为 foo() 采用 const int *?

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

没有.即使 foo() 采用指向 const 的指针,它也可能会丢弃 const 并修改 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);

在这里,通过任何机制修改 x(例如,通过获取指向它的指针并丢弃 const)就是调用未定义行为.所以编译器可以自由地假设你不这样做,它可以将常量 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 与指向 const 的指针相结合可以启用上面忽略的两种优化.我想知道是否有任何编译器实际上实现了这样的优化?(至少 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.

相关文章