我想在C99中创建一个struct
,它封装了一个以空字符结尾的字符串缓冲区以及实际的字符串长度:
typedef unsigned int uint_t;
typedef unsigned char uchar_t;
typedef struct {
uchar_t * buffer;
uint_t length; // excluding null-terminating character
} string_t;
然而,我遇到了一些困扰const
- struct
成员的问题。具体来说,当我想使用一个接受这样的const struct string_t
的函数,并用一个带有const成员的初始化程序来提供它时,编译器会对我大喊大叫。
void show_string_internal(const string_t str) {
printf("%s", str.buffer);
}
void show_string(const uchar_t * buffer, uint_t length) {
const string_t str = // <== tricky assignment here
(const string_t){ buffer, length };
show_string_internal(str);
}
int main() {
uchar_t message[] = "Hello, world.";
show_string(message, sizeof(message) - 1);
return 0;
}
这会在GCC ......:
中对突出显示的行产生警告警告:初始化丢弃&#39; const&#39;指针目标类型的限定符
...在Visual Studio 2015中:
警告C4090:&#39;初始化&#39;:不同的&#39; const&#39;限定符
显然,我在这里做错了。我发现解决这个问题的唯一方法是声明:
typedef struct {
const uchar_t * buffer;
const uint_t length;
} const_string_t;
但是现在我有两种类型而不是一种,所以我需要创建方便的方法来转换两者,我创建声明性糖而不是使用语言功能,所以代码少了可读的。
所以我的问题是,正如标题所示:有没有办法使用成员的const
变量初始化struct
const
?有没有其他方式来达到我希望实现的结果?如果没有,为什么不(请参考官方文件)?
任何帮助都将不胜感激。
答案 0 :(得分:2)
关于指针类型的常量应该“从右到左”读取(并且"const T * buffer"
实际上意味着“指向const内容的指针”,而不是“指向内容的const指针”,也不是“指向const内容的const指针”。
因此,您将使用可变指针到const char缓冲区并将其用于const版本的结构(要求您的const结构具有可变字段 - 这是显示警告的原因)。如果您打算摆脱警告,您必须移动“const”这样的事情:
void show_string(char * const buffer, const int length) { // <== move const to the right of "*"
const string_t str = // <== tricky assignment here
(const string_t) {
buffer, length
};
show_string_internal(str);
}
如果您计划同时拥有const缓冲区,则必须重新定义string_t结构(或作为单独的类型引入):
typedef struct {
const uchar_t * buffer; // <== add "const" here
uint_t length; // excluding null-terminating character
} string_t;
...
void show_string(const char * const buffer, const int length) { // two "const" clauses there
const string_t str = // <== tricky assignment here
(const string_t) {
buffer, length
};
show_string_internal(str);
}
希望这有帮助。
答案 1 :(得分:1)
问题不在于结构层面。
问题在于.buffer
(unsigned char*
)的初始化
char const*
。如果您制作.buffer
char const*
,它会在没有演员的情况下工作,但由于签名不同,您仍然会收到-Wall
的警告。
答案 2 :(得分:0)
您的struct有一个声明为uchar_t *buffer
的成员,并且您尝试使用声明为const char *buffer
的参数对其进行初始化。所以编译器抱怨是因为这样会删除 buffer
所指向的内存的预设常量(这种违规是一个逻辑错误)。根据您的需要/需要,您可以:
另外请注意uchar_t
和char
可能不是同一类型......
答案 3 :(得分:0)
正如其他人所写,问题与const
类型限定符影响struct
聚合类型的方式有关。所有struct
成员值都会成为const
。对于指针成员,它只意味着您可能不会更改指针变量以使其指向其他任何内容,但无论指针指向哪个仍然是可变的。这类似于声明int * const
变量时会发生的情况。
在C99中似乎没有办法赋予const
- 对作为所谓聚合类型一部分的间接(指针)类型的目标。因此,无法将关键字附加到struct
- 类型变量,以表示其指针成员应被视为指向const
类型的指针,例如int const *
。这仅在C99和C11标准中的示例中提及,在第6.7.3节(类型限定符)的末尾。
这个答案是基于回复Jean-BaptisteYuès在Yuval和PSkocik之间回答的信件。
答案 4 :(得分:0)
这只是错误的常数:
typedef unsigned int uint_t; typedef unsigned char uchar_t;
使用正确的大小类型。在C中,它是size_t
typedef struct {
const uchar_t * buffer;
size_t length; // excluding null-terminating character
} string_t;
void show_string(const uchar_t * buffer, size_t length) {
const string_t str = // <== tricky assignment here
(string_t){ buffer, length };
}