我经常使用指向常量对象的指针,就像这样...
const int *p;
这意味着您无法通过 p
更改整数指针所指向的内容。但我也看到过像这样声明的常量指针...
int* const p;
我的理解是,这意味着指针变量本身是常量——你可以整天更改它所指向的整数,但你不能让它指向其他东西。
那会有什么可能的用处呢?
当你在设计嵌入式系统的 C 程序或需要引用相同内存的特殊程序(共享内存的多处理器应用程序)时,你需要常量指针。
例如,我有一个 32 位 MIPs 处理器,它连接了一个 小型 LCD。我必须将我的 LCD 数据写入到内存中的特定端口,然后再发送到 LCD 控制器。
我可以使用 #define 宏定义该数字,但这样我也必须将其强制转换为指针,而当我这样做时,C 编译器可选项就不那么多了。
此外,我可能需要将其设置为 volatile,这也可以进行强制转换,但使用提供的语法——一个指向易失性内存位置的常量指针更容易和清晰。
对于 PC 程序,一个例子就是:如果你设计 DOS VGA 游戏(有一些在线教程很有趣,可以通过学习基本的低级图形知识),则需要写入 VGA 内存,该内存可能被引用为常量指针的偏移量。
它可以让你保护指针不被改变。这意味着你可以保护基于指针永远不会被更改的假设或者避免无意中修改指针,例如:
int* const p = &i;
...
p++; /* Compiler error, oops you meant */
(*p)++; /* Increment the number */
const uint8 *const value
的东西。这声明了指针和它所指向的值是不可修改的(但如果强制转换,则可以修改)。 - James Waldthis
的类型为 C * const
,其中 C
为类类型--您可以更改其指向(即其成员),但不能将其更改为指向 C
的不同实例。对于 const
成员函数,this
的类型为 const C * const
。还有一些(很少遇到)volatile
和 const volatile
成员函数,对于这些函数,this
也具有 volatile
限定符。use at
)。在C语言中,最惯用的方法是声明一个常量指针。请注意,这样的用法也应该具有volatile
限定符。当我想要避免指针的意外修改(如指针算术或在函数内部)时,我总是使用它们。您还可以将它们用于单例模式。
'this' 是一个硬编码常量指针。
struct MyClass
{
char* const ptr;
MyClass(char* str) :ptr(str) {}
void SomeFunc(MyOtherClass moc)
{
for(int i=0; i < 100; ++i)
{
printf("%c", ptr[i]);
moc.SomeOtherFunc(this);
}
}
}
现在,如果编译器知道SomeOtherFunc()不会改变ptr的值,它可以对循环进行优化。加上const关键字后,编译器就知道了这一点,并能够做出相应的假设。没有const关键字,编译器就必须假设SomeOtherFunc会改变ptr。
ptr
是一个公共成员。编译器很难跟踪公共变量在模块间的使用情况。许多编译器甚至不会尝试,只会将其视为volatile
。2)9年前的编译器比较愚笨。 - James Curran我见过一些OLE代码,其中有一个从代码外部传入的对象,要处理它,你需要访问它传入的特定内存。因此,我们使用了const指针来确保函数始终操作通过OLE接口传入的值。
对于这个问题,已经给出了几个好的理由(内存映射设备和简单的防御性编码),但我愿意打赌,在大多数情况下,你看到这种情况实际上是一个错误,而意图是将项目作为指向常量的指针。
我当然没有数据来支持这个直觉,但我仍然会下注。
const
的优化作用是如何的?任何聪明的编译器都可以判断你是否修改了一个变量,并且根据此进行优化,无论你是否声明。 - underscore_d把type*和const type*看作类型本身。这样,你就能明白为什么你可能想要有这些类型的常量。
barrier()
和其他语义。确实需要小心处理值,例如缓存/非缓存、屏障等。这取决于设备类型,而volatile并不总是最佳选项。 - artless noisevolatile
肯定应该在里面;另一方面,许多编译器供应商的头文件似乎并不关心这一点——这可能有点令人恼火(因为即使编译器通常做正确的事情,它们也可能忽略尝试读取寄存器但不对结果进行任何操作的尝试)。 - supercat