阅读本教程后
(https://www.tcpdump.org/pcap.html)
在最底层,作者将一个u_char *packet
指针转换为一个结构。
这样的造型是这样的吗?
假设我有这样的结构
struct 16bits{
int8_t a;
int8_t b;
}
和一个16位序列
0001 0011 0111 1111
如果我将它转换为16位结构,它会是这样的吗?
a = 0001 0011
b = 0111 1111
问题是我是否正确理解了作者的选型。
我知道在结构中填充,但让我们假设编译器暂时不会添加它
发布于 2018-07-17 20:42:16
假设我有这样的结构
结构16位{ int8_t a;int8_t b;}
和一个16位序列
0001 0011 0111 1111
如果我将它转换为16位结构,它会是这样的吗?
A= 0001 0011 b= 0111 1111
我猜你的意思是这样的:
// this points at your 16-bit sequence
unsigned char *input_data = ...
struct 16bits *output_data = ( struct 16bits * ) input_data;
uint8_t a_bits = output_data->a;
uint8_t b_bits = output_data->b;
一般来说,不你不能假设你可以做到这一点。一般来说,这将是a strict aliasing violation和未定义的行为。“严格别名”规则基本上是说,您不能将内存视为不是它的东西-但例外的是,您总是可以一次访问一个char
。int
不是float
。
此外,正如您所提到的,在结构中的字段之间可以进行填充。
但是,在您的特定示例中,几乎可以肯定可以在任何平台上“工作”,因为int8_t
几乎肯定是一个signed char
,struct 16bits
中几乎可以肯定没有填充,并且任何内存都可以作为char
值进行访问。
但是,用double
或int64_t
之类的类型替换char
类型,可能会遇到对齐和填充问题。在某些平台上,这种严格的别名冲突可能会导致使用SIGSEGV
或SIGBUS
的代码失败。
假设8位的char
值,因此int8_t
实际上是一个char
,这是一种完全符合标准的方式来访问应用于16位序列的任何数据类型,就像两个8位的值一样
// assume this points to your 16-bit sequence
unsigned char *input_data = ...
// create a structure that we can actually copy the bits into
struct 16bits output_data;
memcpy( &output_data, input_data, sizeof( output_data ) );
请注意,如果结构包含char
以外的其他类型的元素,则可能存在填充。如果你使用像#pragma pack
这样的东西来消除填充,you can wind up with code that doesn't run on some platforms.
您提供的链接中的代码非常普遍--实际上是未定义的行为。但它是“有效的”,因为编写最流行的已发布代码的x86平台非常、非常、非常容忍未对齐的访问(尽管仍然存在性能损失)。但是这种类型的代码在任何有对齐要求的平台上都不能很好地工作。例如,当在x86上运行得很好的代码在ARM或Google pragma pack sigbus
平台上失败时,你会发现有很多程序员惊讶的例子。
https://stackoverflow.com/questions/51380958
复制相似问题