简体   繁体   English

typedef 指针 const 怪异

[英]typedef pointer const weirdness

please consider the following code:请考虑以下代码:

typedef struct Person* PersonRef;
struct Person {
  int age;
};

const PersonRef person = NULL;

void changePerson(PersonRef newPerson) {
  person = newPerson;
}

For some reason, the compiler is complaining about read-only value not assignable.出于某种原因,编译器抱怨只读值不可分配。 But the const keyword should not make the pointer const.但是const关键字不应该使指针成为 const。 Any ideas?有任何想法吗?

Note that注意

typedef int* intptr;
const intptr x;

is not the same as:不等同于:

const int* x;

intptr is pointer to int. intptr是指向 int 的指针。 const intptr is constant pointer to int , not pointer to constant int . const intptr是指向int常量指针,而不是指向常量int指针。

so, after a typedef pointer, i can't make it const to the content anymore?所以,在 typedef 指针之后,我不能再让它成为内容的常量了?

There are some ugly ways, such as gcc's typeof macro :有一些丑陋的方式,比如 gcc 的typeof 宏

typedef int* intptr;
intptr dummy;
const typeof(*dummy) *x;

but, as you see, it's pointless if you know the type behind intptr .但是,如您所见,如果您知道intptr背后的类型,那将毫无意义。

const PersonRef person = NULL;

is

struct Person*const person= NULL;

so you are consting the pointer and not the object.所以你正在构造指针而不是对象。

While the problem is already solved by the answers above, I do miss the reason why...虽然上面的答案已经解决了问题,但我确实想念为什么......

So maybe as a rule of thumb:所以也许作为一个经验法则:

  1. The const always refers to it's predecessor token. const总是指它的前身标记。
  2. In case there is no such, it's "consting" it's successor token instead.如果没有这样的,它是“consting”,它是后继令牌。

This rule can really help you out for declaring a pointer to const pointers or something equally neat.这个规则真的可以帮助你声明一个指向 const 指针的指针或同样简洁的东西。

Anyway, with this in mind, it should get clear why无论如何,考虑到这一点,应该清楚为什么

struct Person *const person = NULL;

declares a const pointer to a mutable struct.声明一个指向可变结构的const 指针

Think about it, your typedef "groups" the struct Person with the pointer token * .想想看,您的 typedef 将struct Person与指针标记* “分组” So, for writing所以,对于写作

const PersonRef person = NULL;

your compiler sees something like this (pseudo-code):您的编译器会看到类似的内容(伪代码):

const [struct Person *]person = NULL;

As there's nothing to const 's left, it deklares the token to it's right struct Person * constant.由于const的左边没有任何东西,它会将标记释放到它的右边struct Person * constant。

Well I think, this is the reason why I don't like hiding pointers by typedefs, while I do like typedefs as such.好吧,我想,这就是为什么我不喜欢通过 typedef 隐藏指针,而我确实喜欢 typedef 这样的原因。 What about writing写作呢

typedef struct Person { ... } Person;
const Person *person; /*< const person */
Person *const pointer; /*< const pointer to mutable person */

and it should be quite clear to compilers and humans, what you're up to.编译器和人类应该很清楚你在做什么。

Never hide pointers behind typedefs, it is really really bad practice and will only create bugs.永远不要在 typedef 后面隐藏指针,这真的是非常糟糕的做法,只会产生错误。

One such infamous bug is that a typedef:ed pointer type that is declared as const will be treated as a "constant pointer to non-constant data", rather than "a non-constant pointer to constant data" which is what one intuitively expects.一个臭名昭著的错误是,声明为 const 的 typedef:ed 指针类型将被视为“指向非常量数据的常量指针”,而不是“指向常量数据的非常量指针”,这是人们直觉所期望的. This is what happens in your program.这就是您的程序中发生的情况。


Solution:解决方案:

typedef struct
{
  int age;
} Person;

const Person* person = NULL; // non-constant pointer to constant Person

As an addition to Piotr's (accepted) answer, it's possible to avoid GCC-specific typeof :作为 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");

By changing foo_t<T> to foo<T>::type above and/or using boost's version, it's even possible to do this in C++98, though it's only pretty since C++11.通过将foo_t<T>更改为上面的foo<T>::type和/或使用 boost 的版本,甚至可以在 C++98 中做到这一点,尽管它只是自 C++11 以来才漂亮。


Alternatively, use two different typedefs, which also works for cases other than plain pointers.或者,使用两个不同的 typedef,这也适用于普通指针以外的情况。 For example, consider every container's iterator and const_iterator typedefs.例如,考虑每个容器的iteratorconst_iterator类型定义。

you are getting and error你得到和错误

error: assignment of read-only variable ‘person’

on statement在声明中

person = newPerson;

because you have declared person as const so its value is only read only .... const value can not be changed因为你已经将 person 声明为 const 所以它的值是只读的.... const 值不能改变

if you are going to change that vatiable then why you are kepping it const?如果你要改变那个可变的那么你为什么要保持它不变?

remove const keyword your code will works fine删除 const 关键字,您的代码可以正常工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM