我有一个unsigned char指针,其中包含一个结构.现在我想要执行以下操作
unsigned char buffer[24];
//code to fill the buffer with the relevant information.
int len = ntohs((record_t*)buffer->len);
Run Code Online (Sandbox Code Playgroud)
其中record_t结构包含一个名为len的字段.我无法这样做并且收到错误.
error: request for member ‘len’ in something not a structure or union.
Run Code Online (Sandbox Code Playgroud)
然后我尝试了:
int len = ntohs(((record_t*)buffer)->len);
Run Code Online (Sandbox Code Playgroud)
这样才能使操作员优先.那给了我warning:
dereferencing type-punned pointer will break strict-aliasing rules.
然后我宣布
record_t *rec = null;
rec = (record_t*)
Run Code Online (Sandbox Code Playgroud)
我在这做错了什么?
Ker*_* SB 19
根据C和C++标准,通过指向另一种类型的指针访问给定类型的变量是未定义的行为.例:
int a;
float * p = (float*)&a; // #1
float b = *p; // #2
Run Code Online (Sandbox Code Playgroud)
这里#2导致未定义的行为.#1处的分配称为"类型双关语".术语"别名"是指几个不同的指针变量可能指向相同数据的想法 - 在这种情况下,p对数据进行别名a.法律别名是优化的问题(这是Fortran在某些情况下表现出色的主要原因之一),但我们在这里得到的是非法的非法别名.
你的情况也不例外; 您buffer通过指向不同类型的指针(即不是指针char *)访问数据.这根本不允许.
结果是:你首先应该没有数据buffer.
但是如何解决呢?确保你有一个有效的指针!输入punning有一个例外,即通过指向char的指针访问数据,这是允许的.所以我们可以这样写:
record_t data;
record_t * p = &data; // good pointer
char * buffer = (char*)&data; // this is allowed!
return p->len; // access through correct pointer!
Run Code Online (Sandbox Code Playgroud)
关键的区别在于我们将实际数据存储在正确类型的变量中,并且只有在分配了该变量之后才将变量视为字符数组(这是允许的).这里的道德是字符数组总是排在第二位,而真正的数据类型是第一位的.
您正在收到警告,因为您通过指向同一位置的两个不同类型的指针来打破严格别名.
解决这个问题的一种方法是使用工会:
union{
unsigned char buffer[24];
record_t record_part;
};
//code to fill the buffer with the relavent information.
int len = ntohs(record_part.len);
Run Code Online (Sandbox Code Playgroud)
编辑:
严格来说,这并不比原始代码安全得多,但它并没有违反严格别名.