57

在 C++ 中,使用 char 和 char[1] 有什么区别(如果有的话)。

例子:

struct SomeStruct
{
   char x;
   char y[1];
};

unsigned char 是否遵循相同的原因?

4

3 回答 3

39

主要区别只是您用来访问一个字符的语法。

我所说的“访问”是指使用语言中的各种运算符对其进行操作,其中大多数或所有运算符在应用于 acharchar数组时会做不同的事情。这使它听起来好像x并且y几乎完全不同。如果事实上它们都“由”一个字符组成,但是该字符以非常不同的方式表示。

该实现可能会导致存在其他差异,例如它可以根据您使用的结构以不同的方式对齐和填充结构。但我怀疑它会。

运算符差异的一个示例是 char 是可分配的,而数组不是:

SomeStruct a;
a.x = 'a';
a.y[0] = 'a';
SomeStruct b;
b.x = a.x; // OK
b.y = a.y; // not OK
b.y[0] = a.y[0]; // OK

但是不可分配的事实y并没有停止SomeStruct可分配:

b = a; // OK

这一切都与类型无关char。一个类型的对象和一个大小为 1 的类型的数组,就内存中的内容而言几乎相同。

顺便说一句,有一个上下文会产生很大的不同,你“使用”出charand char[1],这有时会让人们误以为数组是真正的指针。不是您的示例,而是作为函数参数:

void foo(char c);     // a function which takes a char as a parameter
void bar(char c[1]);  // a function which takes a char* as a parameter
void baz(char c[12]); // also a function which takes a char* as a parameter

C++ 语言完全忽略bar和的声明中提供的数字。baz显然有人在某些时候觉得它作为一种文档形式对程序员很有用,表明该函数baz期望它的指针参数指向一个 12 字符数组的第一个元素。

在 bar 和 baz 中,c从来没有数组类型——它看起来像一个数组类型,但实际上不是,它只是一个花哨的特殊情况语法,与char *c. 这就是为什么我把引号放在“使用”上——你根本没有真正使用char[1],它只是看起来像它。

于 2010-11-08T01:28:00.660 回答
11

如果您实际上已将构造char y[1]视为生产代码中结构的最后一个成员,那么您很可能遇到了struct hack的实例。

那个短数组是一个真实但可变长度的数组的替代品(回想一下,在 c99 之前,c 标准中没有这样的东西)。程序员总是在堆上分配这样的结构,注意确保分配足够大,以适应他想要使用的数组的实际大小。

于 2010-11-08T01:28:04.610 回答
3

除了史蒂夫强调的用法上的符号差异外,char[1] 还可以传递给 eg template <int N> void f(char(&a)[N]),而 wherechar x = '\0'; f(&x);将不匹配。可靠地捕获数组参数的大小非常方便且令人放心。

它也可能暗示一些不同的东西:要么实际长度可能更长(如 dmckee 所解释),要么内容在逻辑上是 ASCIIZ 字符串(在这种情况下恰好为空),或者字符数组(发生有一个元素)。如果结构是几个相关结构之一(例如,数组大小是模板参数的数学向量,或某些 I/O 操作所需的内存布局的编码),那么与其他字段有一些相似性是完全可能的如果数组可能更大,则建议首选单字符数组,从而使支持代码更简单和/或更普遍适用。

于 2010-11-08T03:15:37.550 回答