阅读完本教程
(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
问题是我是否理解作者的正确投射。
我知道结构中的填充,但可以认为编译器暂时不会添加填充
答案 0 :(得分:1)
让我说我有这个结构
struct 16bits{ 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
,因此{{ 1}},并且始终可以将所有内存作为struct 16bits
值来访问。
将char
类型替换为char
或double
之类的类型,您会遇到对齐和填充问题。在某些平台上,此类严格的别名冲突可能导致代码以int64_t
或SIGSEGV
失败。
假设8位SIGBUS
的值,因此char
实际上是一种int8_t
,这是一种完全符合标准的方式,可将应用于两个16位序列的任何数据类型作为两个8位值应该是
char
请注意,如果结构包含// 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
之类的东西来消除填充,则you can wind up with code that doesn't run on some platforms.
您提供的链接中的代码如此猖ramp-实际上是未定义的行为。但这是“可行的”,因为在最流行的x86平台上编写的代码非常,非常非常宽容地错位了访问(尽管仍然会降低性能)。但是,这种类型的代码在具有对齐要求的任何平台上都无法很好地工作。仅Google pragma pack sigbus
,例如,在ARM或SPARC平台上在x86上运行良好的代码失败时,您会发现很多程序员感到惊讶的例子。