C libpcap API将数据包转换为struct(令人困惑)

时间:2018-07-17 12:06:04

标签: c casting

阅读完本教程

(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

问题是我是否理解作者的正确投射。

我知道结构中的填充,但可以认为编译器暂时不会添加填充

1 个答案:

答案 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和未定义的行为。 “严格别名”规则基本上说,您不能将内存视为不是它的东西-但例外是您始终可以一次访问一个charint不是float

此外,正如您提到的,结构中的字段之间可能会有填充。

不过,在您的特定示例中,几乎可以肯定,它可以在任何平台上“工作”,因为int8_t几乎可以肯定是signed char,因此{{ 1}},并且始终可以将所有内存作为struct 16bits值来访问。

char类型替换为chardouble之类的类型,您会遇到对齐和填充问题。在某些平台上,此类严格的别名冲突可能导致代码以int64_tSIGSEGV失败。

假设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上运行良好的代码失败时,您会发现很多程序员感到惊讶的例子。