C 这段代码是否违反了严格的别名规则?

C 这段代码是否违反了严格的别名规则?,c,type-punning,C,Type Punning,我有一个大的缓冲区,它表示从硬盘加载和解压缩的三维模型文件,该文件后面有一个头和一些顶点、索引和子集数据。起初,我认为我可以计算每个顶点/索引/子集数据开始处的字节偏移量,并简单地将其转换为兼容的指针类型并使用它,但这将打破严格的别名规则。所以一个解决方案是使用memcpy字节来分离顶点/索引/子集数据数组(每个数组都有不同类型的ofc) 您从错误的角度攻击了严格的别名规则。将char数组强制转换到您的结构实际上是一种错误。这不仅是因为别名,还因为路线特性可能不同。不要那样做 你必须反过来做:声

我有一个大的缓冲区,它表示从硬盘加载和解压缩的三维模型文件,该文件后面有一个头和一些顶点、索引和子集数据。起初,我认为我可以计算每个顶点/索引/子集数据开始处的字节偏移量,并简单地将其转换为兼容的指针类型并使用它,但这将打破严格的别名规则。所以一个解决方案是使用memcpy字节来分离顶点/索引/子集数据数组(每个数组都有不同类型的ofc)


您从错误的角度攻击了严格的别名规则。将
char
数组强制转换到您的结构实际上是一种错误。这不仅是因为别名,还因为路线特性可能不同。不要那样做

你必须反过来做:声明你想要的真正类型的结构,然后使用指向该结构的
void*
char*
指针来读取或复制你的数据

这始终保证有效:

  • 字符类型不受严格的别名规则限制
  • 将对象指针传递给函数(
    memcpy
    或其他)总是确保编译器在调用后不能对该对象的状态做出任何假设,因此他必须重新加载整个对象

编辑:也许有些困惑来自奇怪的gcc关于“别名规则”的警告。这只是通过指针强制转换的类型双关所产生的问题的一个方面。通常,通过错误类型(字符类型除外)的指针访问对象可能具有未定义的行为。别名只是其中一个可能会出错的问题。避免它。

您从错误的角度攻击了严格的别名规则。将
char
数组强制转换到您的结构实际上是一种错误。这不仅是因为别名,还因为路线特性可能不同。不要那样做

你必须反过来做:声明你想要的真正类型的结构,然后使用指向该结构的
void*
char*
指针来读取或复制你的数据

这始终保证有效:

  • 字符类型不受严格的别名规则限制
  • 将对象指针传递给函数(
    memcpy
    或其他)总是确保编译器在调用后不能对该对象的状态做出任何假设,因此他必须重新加载整个对象

编辑:也许有些困惑来自奇怪的gcc关于“别名规则”的警告。这只是通过指针强制转换的类型双关所产生的问题的一个方面。通常,通过错误类型(字符类型除外)的指针访问对象可能具有未定义的行为。别名只是其中一个可能会出错的问题。只要避免它。

char*
强制转换为指向结构的指针的问题不是严格的别名规则:
char
类型不受严格的别名规则约束。也就是说,您可以将写为
char
data的数据作为任何其他类型读取,也可以相反地将任何数据作为char数据读取

铸件的问题是对齐。除非您直接从内存分配函数获得
char*
(该函数保证为任何数据生成一个充分对齐的指针),否则可能会出现未对齐的风险,从而导致程序崩溃。使用
memcpy()
可以解决这个问题。但是,如果您可以确定您的
char*
完全对齐,则无需复制

为了避免混淆,这是一个完美的法律规范:

typedef struct Foo {
    ...
} Foo;

void bar() {
    char* buffer = malloc(sizeof(Foo));
    fillBuffer(buffer);
    Foo* header = (Foo*)buffer;    //Ok, buffer is a perfectly aligned pointer.
    readHeader(header);    //Ok, reading data written as char data does not violate strict aliasing rules.
}

char*
强制转换为指向结构的指针的问题不是严格的别名规则:
char
类型不受严格的别名规则限制。也就是说,您可以将写为
char
data的数据作为任何其他类型读取,也可以相反地将任何数据作为char数据读取

铸件的问题是对齐。除非您直接从内存分配函数获得
char*
(该函数保证为任何数据生成一个充分对齐的指针),否则可能会出现未对齐的风险,从而导致程序崩溃。使用
memcpy()
可以解决这个问题。但是,如果您可以确定您的
char*
完全对齐,则无需复制

为了避免混淆,这是一个完美的法律规范:

typedef struct Foo {
    ...
} Foo;

void bar() {
    char* buffer = malloc(sizeof(Foo));
    fillBuffer(buffer);
    Foo* header = (Foo*)buffer;    //Ok, buffer is a perfectly aligned pointer.
    readHeader(header);    //Ok, reading data written as char data does not violate strict aliasing rules.
}

是什么让您认为它可能会破坏别名规则?如果指针类型为,则严格别名不适用char@ouah我真的不知道,我不知道如何让这个模型加载器在不调用未定义行为的情况下工作。别名与通过函数调用执行的修改无关,包括
memcpy
。在这里,编译器必须始终假定对象可能通过调用发生了更改。@bolov只要字节有效(例如,4个字节构成有意义的浮点),我就安全了,对吗?你凭什么认为它会破坏别名规则?如果指针类型为char@ouah我真的不知道,我不知道如何在不调用未定义行为的情况下使此模型加载器工作。别名与通过函数调用执行的修改无关,包括
memcpy
。在这里,编译器必须始终假定对象可能通过调用发生了更改。@bolov只要字节有效(例如,4个字节构成有意义的浮点),我是安全的,对吗?您在OP问题中做出了这样的评论:别名与通过函数调用进行的修改无关。有任何标准参考来支持这一点吗?例如,
void f(float*a){*a=0;}void g(void){int x=0;f((float*)&x)}
从您的注释来看,
f
调用不会破坏别名规则?@ouah,访问