2017-07-05 32 views
5

鉴于这是法律c中数组初始化的背景是什么?

uint8_t bytes[4] = { 1, 2, 3, 4 }; 

这是不是:

uint8_t bytes2[4]; 
bytes2 = { 1, 2, 3, 4 }; 

是什么{ 1, 2, 3, 4 }代表什么?

我假设它既不是右值也不是左值。一个预处理器代码糖果,扩展到某些东西?

+6

不涉及预处理器。它只是_initialization_语法。没有分配。 –

+0

这同样适用于结构... – Attie

+0

一个简单的语法 –

回答

7

{1,2,3,4}初始化列表,只能在其中阵列被声明的线路中使用的特定语法令牌。

这纯粹由C标准语法来调节。背后没有特别的理由,这就是语言的定义。在C语法中,数组不能被赋值,也不能被赋值复制。

但是,您可以通过几种方式躲避语法限制,一次覆盖所有值。最简单的方法就是创建一个临时数组和memcpy:

uint8_t tmp[] = {5,6,7,8}; 
memcpy(bytes, tmp, sizeof bytes); 

另外,使用复合字面常量:

memcpy(bytes, (uint8_t[]){5,6,7,8}, sizeof bytes); 

如果是有道理的具体应用,你也可以包装在阵列一个结构来绕过语法限制:

typedef struct 
{ 
    uint8_t data [4]; 
} array_t; 

... 

array_t bytes = { .data = {1,2,3,4} }; 
array_t tmp = { .data = {5,6,7,8} }; 
bytes = tmp; // works just fine, structs can be copied this way 
+0

UV'd。您可能想要添加'array_t bytes = {.data = {1,2,3,4}};','array_t bytes = {{1,2,3,4}};'和'array_t bytes = { 1,2,3,4};'都是等价的。 – chqrlie

+0

@chqrlie当然......但第一个是最明确和自我记录。第二个是老式的C90,第三个是可疑的风格(虽然它会起作用)。许多编译器给出了第三个版本的警告。 – Lundin

+1

您的评论是完全正确的,我不会使用第三个,因为您提到的原因是第三个,但第二个版本的优点是可移植到不支持C99语法的环境,包括许多C++编译器。 – chqrlie

8

句法如{1,2,3,4};被称为括号内含初始化列表,它是一个初始化程序。它只能用于初始化(对于数组类型)。

引用C11,章§6.7.9

  • P11

为一个标量应是一个单一的表达的初始化,

[阵列是不一个标量类型,所以不适用于我们]

  • P14

字符类型的数组,可以用字符串文字或UTF-8字符串 文字,任选在大括号来初始化。

[我们不是使用字符串这里的文字,所以也并不适用于美国]

  • P16

否则,初始化的对象有骨料或联合类型应为元素或命名成员的初始化程序列表。

[这是我们的兴趣的情况下]

和,P17,

每个括号包围的初始化列表具有相关联的当前对象。当没有 名称存在,当前对象的子对象,以便根据 初始化为当前对象的类型:在增加下标顺序数组元素,结构声明顺序 构件,和一个联合的第一个命名的构件[....]

因此,这里,大括号括起来的列表中的值不是直接“分配”给数组,它们用于初始化数组的各个成员。

OTOH,阵列类型,是不是一个可修改的左值,所以它不能被分配。换句话说,数组变量不能用作赋值运算符的LHS。

为了详细说明,从C11,章§6.5.16

赋值操作员有修改的左值作为其左操作数。

+1

到目前为止,我一直认为'初始化'是'声明+赋值',它似乎不适合上面的例子。你将如何定义初始化? – TheMeaningfulEngineer

+0

@TheMeaningfulEngineer当心,他们有不同的限制。 –

+0

@TheMeaningfulEngineer我已经更新了相关的参考资料,看看是否有帮助。 –

5

初始化和分配是根本不同的事情。而对于C语言,你就必须接受这样的事实,他们是杰出的,但当然,还有它的定义这样一个技术原因:

在许多系统中,你可以有一个数据段在你的可执行文件文件。这部分可以被读/写,并给出一个初始化数组一样

uint8_t foo[] = {1, 2, 3, 4}; // assume this has static storage duration 

编译器可能只是直接决定输出这个确切的字节序列到您的可执行文件。所以有没有代码做任务,当你的程序启动时,数据已经存在于内存中。


OTOH,阵列不能被分配(仅其个别成员)。这就是C的定义,有时也是不幸的。

3

{1,2,3,4}是一个初始化列表。它用于指定具有至少4个元素的对象的初始值,不管它们是数组元素还是包含嵌套对象的结构成员。

不能使用这种语法将值分配给数组作为这样的:

bytes2 = {1,2,3,4}; 

因为语法不被支持,并且数组不是左值。

您可以使用初始化器列表作为被称为复合文字来创建对象,并把它们作为右值的分配,返回值或函数参数C99语法的一部分:

struct quad { int x, y, z, t; }; 

struct quad p; 
p = (struct quad){1,2,3,4}; 

你仍然不能阵列使用因为它们不是左值,但你可以实现与呼叫相同的效果memcpy()

uint8_t bytes2[4]; 
memcpy(bytes2, (uint8_t[4]){1,2,3,4}, sizeof(bytes2)); 

上述声明乃clang编译成一个单一的英特尔指令作为可以在可见