typedef指针const古怪

时间:2011-12-14 12:24:29

标签: c const typedef

请考虑以下代码:

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

const PersonRef person = NULL;

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

由于某种原因,编译器抱怨只读值不可分配。但是const关键字不应该使指针成为常量。有什么想法吗?

6 个答案:

答案 0 :(得分:41)

请注意

typedef int* intptr;
const intptr x;

与:

不同
const int* x;

intptr是指向int的指针。 const intptr是指向int的常量指针,而不是指向常量int的指针。

  

所以,在一个typedef指针之后,我不能再使它成为内容的const?

有一些丑陋的方式,例如gcc的typeof macro

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

但是,如你所知,如果你知道intptr背后的类型,那就毫无意义。

答案 1 :(得分:7)

const PersonRef person = NULL;

struct Person*const person= NULL;

所以你正在构建指针而不是对象。

答案 2 :(得分:6)

虽然上面的答案已经解决了问题,但我确实错过了原因......

所以可能是一条经验法则:

  1. const始终引用它的前任令牌。
  2. 如果没有这样的话,那就是“修改”它的后继令牌。
  3. 这个规则可以真正帮助你声明一个指向const指针或同样整洁的东西的指针。

    无论如何,考虑到这一点,它应该明白为什么

    struct Person *const person = NULL;
    

    向可变结构声明 const指针

    考虑一下,你的typedef “群组” 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 */
    

    并且编制者和人类应该很清楚,你要做什么。

答案 3 :(得分:2)

永远不要隐藏typedef背后的指针,这真的是非常糟糕的做法,只会创建错误。

一个臭名昭着的臭虫是声明为const的typedef:ed指针类型将被视为“指向非常量数据的常量指针”,而不是“指向常量数据的非常量指针”这是什么一个人直观地期待。这就是你的程序中发生的事情。


解决方案:

typedef struct
{
  int age;
} Person;

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

答案 4 :(得分:0)

你得到了错误

error: assignment of read-only variable ‘person’

声明

person = newPerson;

因为您已将person声明为const,因此其值仅为只读.... const值无法更改

如果你打算改变那个可变的那么你为什么要把它改为常量?

删除const关键字,您的代码将正常工作

答案 5 :(得分:0)

作为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,它们也适用于除普通指针之外的其他情况。例如,考虑每个容器的iteratorconst_iterator typedef。