提问人:vdavid 提问时间:4/5/2023 更新时间:4/5/2023 访问量:197
typedef const char* 与 const typedef char*
typedef const char* vs. const typedef char*
问:
我注意到 typedef 指针上的 constness 失去了将其隐式转换为 un-typedef'ed 类型的 const 类型的能力。
由于我显然缺乏适当的词汇来解释这个问题,我将展示一些例子。
以下代码无法使用 GCC 8.3.0 编译
typedef char* char_ptr;
void myFunc(const char_ptr param);
void test() {
const char str[] = "Hello, World!";
myFunc(str);
}
它给出以下错误:
错误:从“const char*”到“char_ptr”{又名“char*”} [-fpermissive] myFunc(str);
我不是在寻找解决方法。我知道很多方法可以解决这个问题,例如强制转换类型或更改函数声明。
我想了解为什么我会遇到这个错误,以及为什么它只发生在 typedef 指针类型的 const 上。
我缩小了一些用例的范围,试图理解编译器何时认为类型是相同的 https://ideone.com/Rk9gD9
typedef char char_t; // Char type
typedef char* char_ptr; // Char pointer
typedef const char* char_const_ptr; // Char const pointer
IS_SAME( char, char ); // Obviously true
IS_SAME( char, float ); // Obviously false
// Testing char_t
IS_SAME( char, char_t ); // true: OK
IS_SAME( const char, char_t ); // false: OK
IS_SAME( char, const char_t ); // false: OK
IS_SAME( const char, const char_t ); // true: OK
// Testing char_ptr
IS_SAME( char*, char_ptr ); // true: OK
IS_SAME( const char*, char_ptr ); // false: OK
IS_SAME( char*, const char_ptr ); // false: OK
IS_SAME( const char*, const char_ptr ); // false: Why?
IS_SAME( char* const, char_ptr ); // false: OK
IS_SAME( char* const, const char_ptr ); // true: Why?
// Testing char_const_ptr
IS_SAME( char*, char_const_ptr ); // false: OK
IS_SAME( const char*, char_const_ptr ); // true: OK
IS_SAME( char* const, char_const_ptr ); // false: OK
我可以正确预测所有情况,除了那些与我预期相反的情况。is_same<const char*, const char_ptr>
is_same<char* const, const char_ptr>
我对这个 SO 主题的理解是,在 typedef 指针类型之前写入实际上等同于在 untypedef 指针类型之后写入(这与上述测试的结果相匹配)。我似乎无法与一种良好的记忆技术联系起来,以提醒自己将来何时应该在 typedef'ed 或 untypedef'ed 类型之前或之后编写 const 类型限定符。const
const
答:
我将用以下代码(传递静态断言)来说明 和 添加的内容:typedef
const
#include <type_traits>
typedef char* char_ptr;
static_assert(std::is_same_v<const char_ptr, char* const>);
// which is the same as
static_assert(std::is_same_v<char_ptr const, char* const>);
const
适用于指针 - 而不是它所指向的指针。 总是适用于它剩下的东西 - 除非左边什么都没有,否则它适用于它的右边,但它通过做 来应用于整个 as-if 。char
const
char_ptr
char_ptr const
本声明:typedef
typedef char* char_ptr;
将名称声明为 类型的别名。也就是说,作为指向非常量的指针的别名。char_ptr
char *
char
所以,这个函数声明:
void myFunc(const char_ptr param);
将其参数声明为指向非常量的常量指针。param
char
它可以被重写为:
void myFunc( char * const param);
注意这一点。为了确定函数的类型,将放弃高级限定符。也就是说,上面的函数声明等价于下面的声明(即不是函数定义):conts
void myFunc( char * param);
例如,您可以声明如下函数:
void myFunc( char * param);
并定义它,例如:
void myFunc( char * const param)
{
std::cout << param << '\n';
}
反之亦然,您可以声明如下函数:
void myFunc( char * const param);
并像这样定义它:
void myFunc( char * param)
{
std::cout << param << '\n';
}
在第一个函数定义中,您不能更改指针本身,例如:
std::cout << ++param << '\n';
但是,在这两个函数定义中,您可以更改指针指向的字符,例如:
*param = 'A';
因为指针,无论它本身是否是常量指针,都是指向非常量字符的指针。
另一方面,在函数中,您声明了一个常量字符数组:test()
const char str[] = "Hello, World!";
使用数组作为参数表达式,它被隐式转换为指向其第一个元素的指针,类型为 。const char *
并且,您正在尝试将此类型的指针传递给函数,该函数的相应参数具有 .也就是说,参数表达式的类型指针指向常量对象,而参数具有指向非常量对象的类型常量指针。const char *
char * const
因此,编译器发出错误。
您可以像这样声明 typedef:
typedef const char* char_ptr;
然后函数声明:
void myFunc(const char_ptr param);
将等同于:
void myFunc(const char * const param);
您可以从以下函数调用该函数:test()
void test() {
const char str[] = "Hello, World!";
myFunc(str);
}
你必须记住,这不是一个马克罗。typedef
您的解释似乎认为您可以在文本上将 typedef(别名)替换到代码中,并且它是一样的。事实并非如此。它创建一个新的类型别名(可以把它想象成在类型周围添加括号)。
typedef char char_t; // Char type
typedef char* char_ptr; // Char pointer
typedef const char* char_const_ptr; // Char const pointer
要记住的另一条规则是束缚左边。除非它在最左边,否则它会绑定右边。因此,将常量从“最左边”向右移动会得到相同的类型。const
我总是将“最左边”移开,因为它使阅读类型更容易(从右到左阅读)。要进行一致的比较,您应该这样做,因为您现在有一个标准位置,您可以进行文本比较。const
const
因此,我会将您的类型视为:
char_t => (char)
char_ptr => (char*)
char_const_ptr => (const char*) => (char const *)
现在看看你的问题:
IS_SAME( const char*, const char_ptr ); // false: Why?
IS_SAME( char* const, const char_ptr ); // true: Why?
const char* => char const *
char* const => char * const
const char_ptr => const (char*) => (char*) const => char * const
查看阅读类型
评论
const
绑定左。除非它在最左边,否则它就会束缚在右边“是一种非常有趣的看待它的方式。谢谢。这也让我想知道为什么 C 标准允许这种令人困惑的符号。
评论
const char_ptr
表示 ,而不是 。您正在使指针 const。char* const
const char*
using
typedef
typedef
char_ptr const
char* const