类型转换的未定义行为?

Undefined behavior with type casting?

举个例子:

typedef struct array_struct {
    unsigned char* pointer;
    size_t length;
} array;

typedef struct vector_struct {
    unsigned char* pointer;
    // Reserved is the amount of allocated memory not being used.
    // MemoryLength = length + reserved;
    size_t length, reserved;
} vector;


// Example Usage:
vector* vct = (vector*) calloc(sizeof(vector), 1);
vct->reserved = 0;
vct->length = 24;
vct->pointer = (unsigned char*) calloc(arr->length, 1);

array* arr = (array*) vct;
printf("%i", arr->length);
free(arr->pointer);
free(arr);

C 似乎按照结构成员在结构中定义的顺序为结构成员分配内存。这意味着如果你投射 vector -> array 你仍然会得到相同的结果,如果你在 array 上执行操作,就像你在 vector 上执行操作一样,因为它们具有相同的成员和成员顺序。

只要你只是从 vector -> array 向下转换,就好像 arrayvector 的泛型类型,你就不应该 运行 遇到任何问题。

尽管类型结构相似,但这是未定义的不良行为吗?

如果你允许类型别名(C 不允许,但大多数编译器默认或通过某些编译标志允许),这是明确定义的行为,如果你禁止这种类型别名,这是未定义的行为(通常称为 "strict aliasing" 因为规则非常严格)。来自C标准的N1570草案:

6.5.2.3

6 One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the complete type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

该部分是关于联合的,但为了使该行为在联合中合法,它限制了填充的可能性,因此要求两个结构共享公共布局和初始填充。所以我们已经准备好了。

现在,对于严格的别名,标准说:

6.5

7 An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object
  • [...]

一个"compatible type"是:

6.2.7

1 Two types have compatible type if their types are the same.

它继续解释 more 并列出了一些案例 "wiggle room" 但其中 none 适用于此处。不幸的是,责任到此为止。这是未定义的行为。

现在,您可以做的一件事是:

typedef struct array_struct {
    unsigned char* pointer;
    size_t length;
} array;

typedef struct vector_struct {
    array array;
    size_t reserved;
} vector;