题 const int *,const int * const和int const *之间有什么区别?


我总是弄乱如何使用 const int*const int * const,和 int const * 正确。是否有一套规则定义了您能做什么和不能做什么?

我想知道在任务,传递给职能等方面所做的所有事情和所有不应做的事情。


995
2017-07-17 13:28


起源


你可以使用 “顺时针/螺旋规则” 解密大多数C和C ++声明。 - James McNellis
cdecl.org 是一个很棒的网站,可以自动翻译C声明。 - Dave Gallagher
@Calmarius: 从类型名称开始的位置开始,尽可能向右移动,必要时向左移动。 int *(*)(char const * const)。从括号右侧开始 * 然后我们必须向左移动: pointer。在parens之外,我们可以向右移动: pointer to function of ...。然后我们必须向左移动: pointer to function of ... that returns pointer to int。重复以扩展参数( ...): pointer to function of (constant pointer to constant char) that returns pointer to int。像帕斯卡这样的易读语言,等效的单行声明会是什么? - Mark K Cowan
@MarkKCowan在Pascal中它会是这样的 function(x:^char):^int。函数类型意味着指向函数的指针,因此不需要指定它,并且Pascal不强制执行const正确性。它可以从左到右阅读。 - Calmarius
“const”左边的第一个东西就是常数。如果“const”是离左边最远的东西,那么它右边的第一个东西就是常数。 - Ngineer


答案:


向后阅读(由...驱动) 顺时针/螺旋规则):

  • int*  - 指向int的指针
  • int const *  - 指向const int的指针
  • int * const  - const指向int的指针
  • int const * const  - const指向const int的指针

现在第一个 const 可以在类型的任何一侧,所以:

  • const int * == int const *
  • const int * const == int const * const

如果你想真的疯了,你可以做这样的事情:

  • int **  - 指向int的指针
  • int ** const  - 指向int的指针的const指针
  • int * const *  - 指向int的const指针的指针
  • int const **  - 指向const int指针的指针
  • int * const * const  - 指向int的const指针的const指针
  • ...

并确保我们清楚const的含义

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

foo 是一个指向常量整数的变量指针。这使您可以更改指向的内容,但不能更改指向的值。最常见的是C风格的字符串,你有一个指向a的指针 const char。您可以更改指向的字符串,但不能更改这些字符串的内容。当字符串本身位于程序的数据段中且不应更改时,这很重要。

bar 是一个指向可以更改的值的常量或固定指针。这就像没有额外语法糖的参考。因为这个事实,通常你会使用你将使用的参考 T* const 指针,除非你需要允许 NULL 指针。


1745
2017-07-17 13:29



我想附加一条经验法则,它可以帮助你记住如何发现'const'是否适用于指针或指向数据:将语句拆分为asterix符号,然后,如果const关键字出现在左侧部分(如'const int * foo') - 它属于指向数据,如果它在右边部分('int * const bar') - 它是关于指针的。 - Michael
@Michael:感谢Michael为了记住/理解const规则这样一个简单的规则。 - sivabudh
这个答案可以归结为前3个单词:向后阅读。 - Shoe
@Jeffrey:只要没有括号,向后读它就会很好。那么,好吧...... 使用typedef - Mooing Duck
+1,虽然更好的总结将是: 向后读指针声明,这意味着,接近@Michael的声明:停止正常的从左到右阅读 第一 星号。 - Wolf


对于那些不了解顺时针/螺旋规则的人: 从变量名称开始,顺时针移动(在这种情况下,向后移动)到下一个 指针 要么 类型。重复直到表达结束。

这是一个演示:

pointer to int

const pointer to int const

pointer to int const

pointer to const int

const pointer to int


235
2017-07-10 02:15



那只是从右到左阅读。 - Dave
@sdotdti在这些情况下是的,但这也适用于更复杂的场景,例如这里的“终极”示例: mydov.blogspot.ch/2012/11/... - Jan Rüegg
@Jan复杂示例的链接没有权限。你可以直接在这里发布,或删除查看限制吗? - R71
@Rog它以前拥有所有开放访问权限...我没有写文章而且我自己也没有访问权限。但是,这是一篇仍然有效的文章的存档版本: archive.is/SsfMX - Jan Rüegg
复杂的例子仍然是从右到左,但包括通常的方式解决括号。整个顺时针旋转的东西并没有让这更容易。 - Matthew Read


我认为一切都已在这里得到解答,但我只想补充一点,你应该提防 typedef小号!它们不仅仅是文本替换。

例如:

typedef char *ASTRING;
const ASTRING astring;

的类型 astring 是 char * const不是 const char *。这是我总是倾向于提出的一个原因 const 在类型的右边,从不在开始。


123
2017-07-17 13:39



对我来说,这是永远不会输入指针的原因。我没有看到像这样的好处 typedef int* PINT (我假设它来自C中的实践,许多开发人员继续这样做)。太好了,我取而代之 * 用一个 P,它不会加快打字速度,加上你提到的问题。 - Mephane
@Mephane - 我可以看到。然而,对我来说,为了继续使用一个特殊的语法规则(关于“const”放置)而不是避免使用特殊的语法规则,以避免使用一个好的语言特性,所以你可以安全地使用这种语言功能。 。 - T.E.D.
@Mephane PINT 确实是一个相当愚蠢的typedef使用,特别是因为它让我觉得系统商店使用啤酒作为记忆。但是,typedef对于处理函数指针非常有用。 - ApproachingDarknessFish
@KazDragon感谢!没有它,我会搞砸所有那些类型的东西 PVOID, LPTSTR Win32 api中的东西! - David Lee
@Mephane:在使用某些传统宏时,我必须使用pSomething几次,这些宏被编写为接受类型,但如果类型不是单个字母数字标识符,则会分解。 :) - Groo


几乎所有人都指出:

有什么区别 const X* pX* const p 和 const X* const p

你必须阅读指针声明   右到左。

  • const X* p 表示“p指向一个X为常量”:X对象不能通过p更改。

  • X* const p 表示“p是指向非const的X的const指针”:您不能更改指针p本身,但可以通过p更改X对象。

  • const X* const p 表示“p是一个指向X的常量指针”:你不能改变指针p本身,也不能通过p改变X对象。


44
2017-07-17 13:36





  1. 常量参考:

    对变量(此处为int)的引用,它是常量。我们主要将变量作为引用传递,因为引用的大小小于实际值,但是存在副作用,这是因为它就像实际变量的别名。我们可能会通过完全访问别名来意外更改主变量,因此我们将其设置为常量以防止此副作用。

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. 常量指针

    一旦常量指针指向变量,它就不能指向任何其他变量。

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. 指向常数的指针

    一个指针,通过它可以不改变它指向的变量的值,称为指向常量的指针。

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. 指向常量的常量指针

    指向常量的常量指针是一个指针,既不能改变它指向的地址,也不能改变保存在该地址的值。

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

39
2018-05-17 20:21





这个问题表明 恰恰 为什么我喜欢按照我在问题中提到的方式做事 类型id可接受后是const吗?

简而言之,我发现记住规则的最简单方法是“const”  它适用的东西。所以在你的问题中,“int const *”意味着int是常量,而“int * const”意味着指针是常量。

如果有人决定把它放在最前面(例如:“const int *”),作为一种特殊的例外情况,它适用于它后面的东西。

许多人喜欢使用这个特殊的例外,因为他们认为它看起来更好。我不喜欢它,因为它是一个例外,因此混淆了事情。


15
2017-07-17 13:52



我对这个问题很感兴趣。逻辑上它是有道理的。但是大多数c ++开发人员都会写 const T* 它变得更自然了。你多久使用一次 T* const 无论如何,通常参考会做得很好。当我想要一个时,我有点喜欢这一切 boost::shared_ptr<const T> 而是写了 const boost::shared_ptr<T>。同一问题在略有不同的背景下。 - Matt Price
实际上,我使用常量指针比使用常量更频繁。此外,你必须考虑如何在指针指针(等等)的情况下作出反应。不可否认,这些都是罕见的,但以一种可以用applomb处理这些情况的方式思考问题会很好。 - T.E.D.
将const放在类型右侧的另一个好处是现在所有东西都在左边 const 是const的类型,其右边的所有内容都是const。采取 int const * const * p; 举个例子。不,我通常不会这样写,这只是一个例子。第一 const:type int,而const是const的内容是const指针的内容 p。第二个const:type是指针 const int,const oblect是内容 p - dgnuff


一般规则就是 const 关键字适用于它之前的内容。例外,一个开始 const 适用于以下内容。

  • const int* 是相同的 int const* 和手段 “指向常量int的指针”
  • const int* const 是相同的 int const* const 和手段 “常量指针指向常量int”

编辑: 对于Dos和Don'ts,如果 这个答案 是不够的,你能更准确地了解你想要的吗?


14
2017-07-17 13:30



这是第一个让我信服的答案。 - pwuertz