【问题标题】:typedef pointer const weirdnesstypedef 指针 const 怪异
【发布时间】:2021-12-31 12:16:26
【问题描述】:

请考虑以下代码:

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。

标签: c constants typedef


【解决方案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】:

你得到错误

error: assignment of read-only variable ‘person’

关于声明

person = newPerson;

因为你已经将 person 声明为 const,所以它的值是只读的 ....const 值不能改变

如果您要更改该变量,那么为什么要保持它为常量?

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

【讨论】:

  • 是的,当然,我只是想知道为什么指针是 const 而不是它指向的内容。这就是我所期望的......
【解决方案4】:

永远不要将指针隐藏在 typedef 后面,这是非常糟糕的做法,只会产生错误。

一个臭名昭著的错误是,声明为 const 的 typedef:ed 指针类型将被视为“指向非常量数据的常量指针”,而不是“指向常量数据的非常量指针”,这就是一个直观的期望。这就是您的程序中发生的情况。


解决方案:

typedef struct
{
  int age;
} Person;

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

【讨论】:

    【解决方案5】:

    虽然上面的答案已经解决了这个问题,但我确实想念为什么......

    所以也许根据经验:

    1. const 始终指代它的前任令牌。
    2. 如果没有这样的,它会“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 */
    

    编译器和人类应该很清楚你在做什么。

    【讨论】:

      【解决方案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&lt;T&gt; 更改为 foo&lt;T&gt;::type 和/或使用 boost 的版本,甚至可以在 C++98 中执行此操作,尽管它仅在 C++11 之后才很漂亮。


      或者,使用两种不同的 typedef,这也适用于普通指针以外的情况。例如,考虑每个容器的 iteratorconst_iterator 类型定义。

      【讨论】:

        猜你喜欢
        • 2011-01-16
        • 2011-01-10
        • 2011-03-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多