简体   繁体   English

通过转换为结构来分配给数组

[英]Assigning to an array by casting to a struct

Why does the following code work? 为什么以下代码有效?

#include <stdio.h>
#define LEN 12

typedef struct
{
    char buffer[LEN];
} string;

int main()
{
    char buffer1[LEN] = "Hello World";
    char buffer2[LEN];

    *(string*)buffer2 = *(string*)buffer1;

    printf("%s",buffer2);
    return 0;
}

As far as I understand, I cannot assign one array to another. 据我了解,我不能将一个数组分配给另一个。

C permits assigning one struct to another of the same type, and the semantics of doing so are defined in terms of the struct representation, as opposed to a member-by-member copy. C允许将一个结构分配给相同类型的另一个结构,并且这样做的语义是根据结构表示来定义的,而不是逐个成员复制。 That a struct representation encompasses the representation of an array does not mean that assigning the value of a struct that contains an array to another struct violates C's prohibition against assigning one array to another. 结构表示形式包含数组的表示形式并不意味着将包含数组的结构值分配给另一个结构违反了C的禁止将一个数组分配给另一个数组的禁止。

C furthermore guarantees that the address of the first member of a struct is the same as the address of the struct itself, and it permits object pointers to be cast among different pointer types. C还保证结构的第一个成员的地址与结构本身的地址相同,并且它允许在不同的指针类型之间强制转换对象指针。 In that case, the result of such a conversion is not guaranteed to be correctly aligned, and if it is not then dereferencing that result produces undefined behavior. 在那种情况下,不能保证这种转换的结果正确对齐,如果不正确,则取消引用该结果会产生不确定的行为。

On the other hand, the compiler is free to include trailing padding in struct representations. 另一方面,编译器可以自由地在结构表示中包括尾随填充。 Oftentimes that is done for alignment purposes. 通常这样做是为了对齐目的。 If your compiler does that for your struct -- which it likely will do if it applies a 64-bit or greater alignment requirement to it -- then your assignment produces undefined behavior. 如果编译器对结构执行此操作(如果对结构应用64位或更高的对齐要求,则可能执行此操作),则分配会产生未定义的行为。 In that case, if it appears to work then that's because you got lucky. 在这种情况下,如果它看起来可行,那是因为您很幸运。

If, however, it turns out that neither of the above sources of undefined behavior applies, then it is indeed reasonable to expect the code to work as expected. 但是,如果发现以上未定义行为的来源均不适用,那么期望代码按预期工作确实是合理的。 Inasmuch as it is tricky to predict whether that will be the case, however, you would be well advised to avoid code like this. 由于很难预测是否会发生这种情况,因此,建议您避免使用这样的代码。

A better question might be why C disallows array copying. 一个更好的问题可能是为什么C不允许数组复制。 There are likely several reasons, but I think the deepest one is simply for consistency. 可能有多种原因,但我认为最深层的原因只是为了保持一致性。 In almost all contexts, when an an expression or sub-expression evaluates to an array, that value decays to a pointer to the first array element. 在几乎所有上下文中,当一个表达式或子表达式对数组求值时,该值将衰减到指向第一个数组元素的指针。 That includes the subexpressions constituting the operands to an = operator. 这包括构成=运算符的操作数的子表达式。 So in normal C expressions, an array assignment would actually be a pointer assignment, and one that did not have the intended semantics. 因此,在正常的C表达式中,数组分配实际上将是指针分配,而没有预期的语义。 One would have had to carefully craft an appropriate special case for that situation in order to allow for array assignment. 为了允许分配数组,必须为这种情况精心设计适当的特殊情况。

As pointed out in the comments you are not assigning an array to another but you are assigning a struct to another by means of the cast. 如注释中所指出的,您没有将数组分配给另一个,而是通过强制转换将结构分配给了另一个。 Assigning a struct result in copying all the elements (in case of a simple struct, see this post ). 分配结构会导致复制所有元素(如果是简单结构,请参见此文章 )。 The code however it's really bad and you can break it by simply adding another field to the struct. 但是,代码确实很糟糕,您可以通过在结构中添加另一个字段来破坏它。

From your comment "As far as I understand, I cannot assign one array to another." 根据您的评论“据我所知,我无法将一个数组分配给另一个。” it seems that you created the struct to circumvent the inability to copy one string to another by casting your buffers to the struct in assignment. 似乎您创建了该结构,以通过将缓冲区强制转换为该结构来避免无法将一个字符串复制到另一个字符串。

This happened to work this time, but it won't always work; 这次碰巧成功了,但它并不总是有效。 structs often have padding and alignment bits between fields. 结构通常在字段之间具有填充和对齐位。

If you want to copy one string to another in C, use the strcpy or strncpy functions (or, in the case of wchar_t type strings, wcscpy and wcsncpy ). 如果要在C语言中将一个字符串复制到另一个字符串,请使用strcpystrncpy函数(或者,对于wchar_t类型的字符串,请使用wcscpywcsncpy )。

If you want to copy one array of an arbitrary type to another, use a for loop where you copy each index one by one, or the memcpy function. 如果要将一个任意类型的数组复制到另一个数组,请使用for循环,在其中逐个复制每个索引或使用memcpy函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM