typedef 指针 const 怪异
Posted
技术标签:
【中文标题】typedef 指针 const 怪异【英文标题】:typedef pointer const weirdness 【发布时间】:2011-12-14 12:24:28 【问题描述】:请考虑以下代码:
typedef struct Person* PersonRef;
struct Person
int age;
;
const PersonRef person = NULL;
void changePerson(PersonRef newPerson)
person = newPerson;
由于某种原因,编译器抱怨只读值不可赋值。但是const
关键字不应该使指针变为常量。有什么想法吗?
【问题讨论】:
"但是 const 关键字不应该使指针变为 const。"嗯?简短的回答:不要使用 typedef,它们只会让你感到困惑。记住它们,直到你需要它们。 @wildplasser:“不要使用 typedefs”不是一个好建议。也许“不要在 typedef 后面隐藏指针”更合适...... 我不同意。这是一个很好的建议。将结构隐藏在 typedef 后面就像隐藏指针一样令人困惑。它只会污染你的心理命名空间。即使没有语法高亮,我读“struct person *p”也比“pPerson p”更容易、更快。 @wildplasser:那你如何应对 C++? @struct wildplasser 如果 struct 你觉得 typdef:ed structs 令人困惑,那么 struct 恐怕你在使用任何 struct 编程语言时都会遇到问题,除了 struct 汇编器。 struct 世界中的其他 struct 程序员显然不同意 struct you。 【参考方案1】:注意
typedef int* intptr;
const intptr x;
不等于:
const int* x;
intptr
是指向 int 的指针。 const intptr
是指向int
的常量指针,而不是指向常量int
的指针。
所以,在 typedef 指针之后,我不能再将它变成内容了?
还有一些丑陋的方式,比如gcc的typeof macro:
typedef int* intptr;
intptr dummy;
const typeof(*dummy) *x;
但是,如您所见,如果您知道intptr
背后的类型,那将毫无意义。
【讨论】:
所以,在 typedef 指针之后,我不能再将它变成内容了? @Johannes 是的;将其添加到您的武器库中 not 以隐藏 typedef 中的指针。这几乎从来都不是一个好主意,而且有很多理由认为它是一个坏主意。【参考方案2】:const PersonRef person = NULL;
是
struct Person*const person= NULL;
所以你是在构造指针而不是对象。
【讨论】:
所以,在 typedef 指针之后,我不能再将它变成内容了? 是的,确切地说,指针的typedef
通常是一个坏主意的原因之一。【参考方案3】:
虽然上面的答案已经解决了问题,但我确实想念为什么......
所以也许根据经验:
const
始终指代它的前任令牌。
如果没有这样的,它会“consting”它的后继令牌。
这条规则真的可以帮助你声明一个指向 const 指针的指针或同样简洁的东西。
无论如何,考虑到这一点,应该清楚为什么
struct Person *const person = NULL;
声明一个指向可变结构的 const 指针。
想想看,你的 typedef "groups" struct Person
和指针标记 *
。
所以,对于写作
const PersonRef person = NULL;
您的编译器会看到类似这样的内容(伪代码):
const [struct Person *]person = NULL;
由于const
的左侧没有任何内容,它会将令牌放到右侧的struct Person *
常量。
我想,这就是我不喜欢用 typedef 隐藏指针的原因,而我喜欢 typedef 本身。怎么写
typedef struct Person ... Person;
const Person *person; /*< const person */
Person *const pointer; /*< const pointer to mutable person */
编译器和人类应该很清楚你在做什么。
【讨论】:
【参考方案4】:永远不要在 typedef 后面隐藏指针,这真的是非常糟糕的做法,只会产生错误。
一个臭名昭著的错误是,声明为 const 的 typedef:ed 指针类型将被视为“指向非常量数据的常量指针”,而不是“指向常量数据的非常量指针”,这就是一个直观的期望。这就是您的程序中发生的情况。
解决方案:
typedef struct
int age;
Person;
const Person* person = NULL; // non-constant pointer to constant Person
【讨论】:
【参考方案5】:你得到错误
error: assignment of read-only variable ‘person’
关于声明
person = newPerson;
因为你已经将 person 声明为 const,所以它的值是只读的 ....const 值不能改变
如果您要更改该变量,那么为什么要保持它为常量?
删除 const 关键字,您的代码将正常工作
【讨论】:
是的,当然,我只是想知道为什么指针是 const 而不是它指向的内容。这就是我所期望的......【参考方案6】:作为对 Piotr(已接受)答案的补充,可以避免 GCC 特定的typeof
:
static_assert(std::is_same<const int *, std::add_const_t<std::remove_pointer_t<intptr>> *>::value, "not same via type_traits");
static_assert(std::is_same<const int *, std::remove_reference_t<decltype(std::as_const(*intptr()))>*>::value, "not same via decltype");
通过将上面的 foo_t<T>
更改为 foo<T>::type
和/或使用 boost 的版本,甚至可以在 C++98 中执行此操作,尽管它仅在 C++11 之后才很漂亮。
或者,使用两种不同的 typedef,这也适用于普通指针以外的情况。例如,考虑每个容器的 iterator
和 const_iterator
类型定义。
【讨论】:
以上是关于typedef 指针 const 怪异的主要内容,如果未能解决你的问题,请参考以下文章