【问题标题】:What use are const pointers (as opposed to pointers to const objects)?const 指针(与指向 const 对象的指针相反)有什么用?
【发布时间】:2010-09-18 04:59:29
【问题描述】:

我经常使用指向 const 对象的指针,像这样......

const int *p;

这仅仅意味着您不能通过p 更改p 指向的整数。但我也看到了对 const 指针的引用,声明如下......

int* const p;

据我了解,这意味着指针变量本身 是常量——您可以更改它整天指向的整数,但不能让它指向其他东西。

那有什么可能的用途?

【问题讨论】:

    标签: c++ c constants


    【解决方案1】:

    当您为嵌入式系统设计 C 程序或需要引用同一内存的特殊用途程序(共享内存的多处理器应用程序)时,您需要常量指针。

    例如,我有一个32 bit MIPs processor,它附加了一个little LCD。我必须将 LCD 数据写入内存中的特定端口,然后将其发送到 LCD 控制器。

    我可以#define 该数字,但我还必须将其转换为指针,而当我这样做时,C 编译器没有那么多选项。

    此外,我可能需要它是易失性的,也可以强制转换,但使用提供的语法更容易和更清晰 - 一个指向易失性内存位置的 const 指针。

    对于 PC 程序,一个例子是:如果你设计 DOS VGA 游戏(网上有教程很有趣,可以学习基本的底层图形),那么你需要写入 VGA 内存,可以参考作为 const 指针的偏移量。

    -亚当

    【讨论】:

    • 次要 nitpick:对于内存映射设备,您当然(不是“可能”)需要将该项目标记为 volatile - 否则您无法确定编译器是否或何时会实际发出读取或写操作。
    • 您“可能”需要 volatile 是正确的。您可以根据设备使用barrier() 和其他语义。确实,您需要仔细处理这些值。即缓存/无缓存、屏障等。这取决于设备的类型,volatile 并不总是最佳选择。
    • @MichaelBurr:我同意你的观点,volatile 肯定应该在那里;另一方面,许多编译器供应商的头文件似乎并不在意——这可能有点烦人(因为即使编译器通常做正确的事情,他们也可能会忽略读取寄存器的尝试,但对结果)。
    【解决方案2】:

    它允许您保护指针不被更改。这意味着您可以保护基于指针永不更改或无意修改的假设,例如:

    int* const p = &i;
    
    ...
    
    p++;     /* Compiler error, oops you meant */
    (*p)++;  /* Increment the number */
    

    【讨论】:

    • 我以前从未见过,我同意这是一个非常有用的技巧。
    • 这不是一个把戏:)。我尝试在可能的情况下将 const 与函数参数一起使用,以便清楚地知道该函数不会修改传入的字符串或结构。
    • 令人困惑的是 const 在一个声明中经常出现两次,而且它实际上可能出现在几个不同的位置。通常它可能显示为const uint8 *const value 之类的东西。这声明了指针和它指向的值是不可修改的(但可以被强制转换)。
    【解决方案3】:

    另一个例子: 如果您知道它的初始化位置,则可以避免将来的 NULL 检查。 编译器保证指针永远不会改变(为 NULL)……

    【讨论】:

    • 在 C 中。在 C++ 中,在您的特定情况下(即非 NULL 指针),您使用引用代替。
    【解决方案4】:

    在任何非 const C++ 成员函数中,this 指针的类型为 C * const,其中 C 是类类型——您可以更改它指向的内容(即它的成员),但您可以不要将其更改为指向C 的不同实例。对于const 成员函数,this 的类型为const C * const。还有(很少遇到)volatileconst volatile 成员函数,this 也有 volatile 限定符。

    【讨论】:

      【解决方案5】:

      一种用途是在低级(设备驱动程序或嵌入式)代码中,您需要引用映射到输入/输出设备(如硬件引脚)的特定地址。某些语言允许您链接特定地址的变量(例如,Ada 有use at)。在 C 中,最惯用的方法是声明一个常量指针。请注意,此类用法还应具有volatile 限定符。

      其他时候只是防御性编码。如果您有一个不应该更改的指针,明智的做法是声明它不能更改。这将允许编译器(和 lint 工具)检测修改它的错误尝试。

      【讨论】:

        【解决方案6】:

        当我想避免对指针的意外修改(例如指针算术,或在函数内部)时,我总是使用它们。您也可以将它们用于单例模式。

        'this' 是一个硬编码的常量指针。

        【讨论】:

          【解决方案7】:

          与“const int”相同......如果编译器知道它不会改变,它可以是基于此的优化假设。

          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,编译器知道这一点,并且可以做出假设。没有它,编译器必须假设 SomeOtherFunc 会改变 ptr。

          【讨论】:

          • SomeOtherFunc 是否必须使用 const 指针参数声明才能编译?这难道不是编译器知道 SomeOtherFunc 不会改变指针的方式吗?所以将本地指针声明为 const 似乎没有帮助。
          • 安德鲁:我认为你把 ptr 和这个混淆了
          • @Andrew:不。SomeOtherFunc 完全允许更改 MyClass 对象的任何其他部分。
          • const 对优化有何影响?任何聪明的编译器都可以判断你是否修改了一个变量,如果可以根据它进行优化,不管你你会不会。
          • @underscore_d 1) ptr 是公共成员。编译器很难跨模块跟踪公共变量的使用。许多人甚至不会尝试,只会将其视为volatile 2) 9 年前编译器更笨。
          【解决方案8】:

          我见过一些 OLE 代码,其中有一个从代码外部传入的对象,要使用它,你必须访问它传入的特定内存。所以我们使用 const 指针来确保函数始终操作的值比通过 OLE 接口传入的值。

          【讨论】:

            【解决方案9】:

            已经给出了几个很好的理由作为这个问题的答案(内存映射设备和只是简单的旧防御性编码),但我敢打赌,在大多数情况下,你看到这实际上是一个错误并且意图是必须 item 是一个指向 const 的指针。

            我当然没有数据支持这种预感,但我还是会打赌。

            【讨论】:

            • 我经常使用它进行优化。
            • @DavidG 确切地说,const 对优化有什么影响?任何聪明的编译器都可以判断你是否修改了一个变量,如果可以根据它进行优化,不管你你会不会。
            • 早在 2008 年我写这篇评论时,它就在某些设备上出现了……但从那以后世界发生了很大变化,现在编译器也有了很大的改进。
            【解决方案10】:

            type*const type* 视为类型本身。然后,您就会明白为什么您可能想要拥有这些类型的 const。

            【讨论】:

            • 是的,那个类型基本上是一个int。
            【解决方案11】:

            始终将指针视为 int。这意味着

            object* var;
            

            其实可以认为是

            int var;
            

            所以,一个 const 指针仅仅意味着:

            const object* var;
            

            变成

            const int var;
            

            因此你也不能改变指针指向的地址,仅此而已。为防止数据更改,您必须将其设为指向 const 对象的指针。

            【讨论】:

            • 指针不是 ints,在很多方面。此外,这个问题非常明确地表述为关于const 指针,而不是指向const 对象的指针。但无论如何,你把它们弄错了。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-09-10
            • 1970-01-01
            • 1970-01-01
            • 2021-05-10
            • 1970-01-01
            • 2012-11-07
            • 2022-01-04
            相关资源
            最近更新 更多