c语言如何给位域变量赋值,C语言的位域赋值问题

  • Post author:
  • Post category:其他


系统:ubuntu 11.04  little-end

描述:这个问题是在研究TS包头解析时遇到的,用两种方式取TS包头,但结果不同

耗时:2天

程序:

1. 使用正常顺序方式定义TS包头结构体,然后将TS包头数据拷贝到包头结构体中。

void bob_get_packet_header_mem_cpy_1(unsigned char *ts_package)

{

printf(” [%s]:\n”, __func__);

printf(” Package Source Data: “);

unsigned char *p = ts_package;

while(p < (ts_package + sizeof(TS_packet_header))){

printf(“%02x “, *p);

p++;

}

printf(” (0x%04x)\n”, *(unsigned int *)ts_package);

struct bob_TS_packet_header

{

unsigned int sync_byte :8;

unsigned int transport_error_indicator :1;

unsigned int payload_unit_start_indicator :1;

unsigned int transport_priority :1;

unsigned int PID :13;

unsigned int transport_scrambling_control :2;

unsigned int adaptation_field_control :2;

unsigned int continuity_counter :4;

}header;

memcpy((void *)&header, ts_package, sizeof(header));

printf(” sync_byte(8b): 0x%02X (%u) %s\n”, header.sync_byte, header.sync_byte, (header.sync_byte == 0x47 ? “” : “(sync error)”));

printf(” transport_error_indicator(1b): 0x%02X (%u) %s\n”, header.transport_error_indicator, header.transport_error_indicator, (header.transport_error_indicator == 0x00 ? “” : “(packet error)”));

printf(” payload_unit_start_indicator(1b): 0x%02X (%u)\n”, header.payload_unit_start_indicator, header.payload_unit_start_indicator);

printf(” transport_priority(1b): 0x%02X (%u)\n”, header.transport_priority, header.transport_priority);

printf(” PID(13b): 0x%04X (%u)\n”, header.PID, header.PID);

printf(” transport_scrambling_control(2b): 0x%02X (%u) %s\n”, header.transport_scrambling_control, header.transport_scrambling_control, (header.transport_scrambling_control == 0x00 ? “(not scrambled)” : “(scrambled)”));

printf(” adaptation_field_control(2b): 0x%02X (%u) %s\n”, header.adaptation_field_control, header.adaptation_field_control, (header.adaptation_field_control == 0x00 ? “(no adap_field, no payload)” : header.adaptation_field_control == 0x01 ? “(no adap_field, payload only)” : header.adaptation_field_control == 0x10 ? “(adap_field only, no payload)” : “(adap_field followed by payload)”));

printf(” continuity_counter(4b): 0x%02X (%u)\n”, header.continuity_counter, header.continuity_counter);

printf(“\n”);

}

2. 使用正常顺序方式定义TS包头结构体,使用buffer存储TS包头,然后通过位移过滤方式将值赋给TS包头结构体的成员。

void bob_get_packet_header_bit_shift(unsigned char *ts_package)

{

printf(” [%s]:\n”, __func__);

printf(” Package Source Data: “);

unsigned char *p = ts_package;

while(p < (ts_package + sizeof(TS_packet_header))){

printf(“%02x “, *p);

p++;

}

printf(” (0x%04x)\n”, *(unsigned int *)ts_package);

struct bob_TS_packet_header

{

unsigned int sync_byte :8;

unsigned int transport_error_indicator :1;

unsigned int payload_unit_start_indicator :1;

unsigned int transport_priority :1;

unsigned int PID :13;

unsigned int transport_scrambling_control :2;

unsigned int adaptation_field_control :2;

unsigned int continuity_counter :4;

}header;

unsigned char buf[4];

memcpy(buf, ts_package, sizeof(header));

int i;

for(i=0; i<4; i++){

printf(“%x[%d] “, buf[i], i);

}

printf(“\n”);

/* *

* buf:

* Hex: 0x47 0x40 0x00 0x10

* Bin: 0100 0111 0100 0000 0000 0000 0001 0000

* buf[0]: 0100 0111|

* buf[1]: 0|1|0|0

* buf[2]: 0000 0000

* buf[3]: 0000|

* buf[4]: 00|01| 0000

*/

header.sync_byte = buf[0];

header.transport_error_indicator = buf[1] >> 7;

header.payload_unit_start_indicator = buf[1] >> 6 & 0x01;

header.transport_priority = buf[1] >> 5 & 0x01;

header.PID = (buf[1] & 0x1F) << 8 | buf[2];

header.transport_scrambling_control = buf[3] >> 6;

header.adaptation_field_control = buf[3] >> 4 & 0x03;

header.continuity_counter = buf[3] & 0x0F;

printf(” sync_byte(8b): 0x%02X (%u) %s\n”, header.sync_byte, header.sync_byte, (header.sync_byte == 0x47 ? “” : “(sync error)”));

printf(” transport_error_indicator(1b): 0x%02X (%u) %s\n”, header.transport_error_indicator, header.transport_error_indicator, (header.transport_error_indicator == 0x00 ? “” : “(packet error)”));

printf(” payload_unit_start_indicator(1b): 0x%02X (%u)\n”, header.payload_unit_start_indicator, header.payload_unit_start_indicator);

printf(” transport_priority(1b): 0x%02X (%u)\n”, header.transport_priority, header.transport_priority);

printf(” PID(13b): 0x%04X (%u)\n”, header.PID, header.PID);

printf(” transport_scrambling_control(2b): 0x%02X (%u) %s\n”, header.transport_scrambling_control, header.transport_scrambling_control, (header.transport_scrambling_control == 0x00 ? “(not scrambled)” : “(scrambled)”));

printf(” adaptation_field_control(2b): 0x%02X (%u) %s\n”, header.adaptation_field_control, header.adaptation_field_control, (header.adaptation_field_control == 0x00 ? “(no adap_field, no payload)” : header.adaptation_field_control == 0x01 ? “(no adap_field, payload only)” : header.adaptation_field_control == 0x10 ? “(adap_field only, no payload)” : “(adap_field followed by payload)”));

printf(” continuity_counter(4b): 0x%02X (%u)\n”, header.continuity_counter, header.continuity_counter);

printf(“\n”);

}

3.  使用倒序方式定义TS包头结构体,并将原始的TS包头数据颠倒4->1, 3->2, 2->3, 1->4,然后将颠倒后的TS包头数据拷贝到包头结构体中。

struct _TS_packet_header//defined in reverse order

{

unsigned int continuity_counter :4 ;

unsigned int adaptation_field_control :2 ;

unsigned int transport_scrambling_control :2 ;

unsigned int PID :13 ;

unsigned int transport_priority :1 ;

unsigned int payload_unit_start_indicator :1 ;

unsigned int transport_error_indicator :1 ;

unsigned int sync_byte :8 ;

};

typedef struct _TS_packet_header TS_packet_header;

void TS_header_decode(TS_packet_header *p_header,byte* ts_package)

{

*(byte *)p_header = *(ts_package + 3);

*((byte *)(p_header) + 1) = *(ts_package + 2);

*((byte *)(p_header) + 2) = *(ts_package + 1);

*((byte *)(p_header) + 3) = *(ts_package);

printf(” Package Source Data: “);

unsigned char *p = (unsigned char *)p_header;

while(p < ((unsigned char *)p_header + sizeof(TS_packet_header))){

printf(“%02x “, *p);

p++;

}

printf(” (0x%04x)\n”, *(unsigned int *)p_header);

printf(“PACKET HEADER:\n”);

printf(” sync_byte(8b): 0x%02X (%u) %s\n”, p_header->sync_byte, p_header->sync_byte, (p_header->sync_byte == 0x47 ? “” : “(sync error)”));

printf(” transport_error_indicator(1b): 0x%02X (%u) %s\n”, p_header->transport_error_indicator, p_header->transport_error_indicator, (p_header->transport_error_indicator == 0x00 ? “” : “(packet error)”));

printf(” payload_unit_start_indicator(1b): 0x%02X (%u)\n”, p_header->payload_unit_start_indicator, p_header->payload_unit_start_indicator);

printf(” transport_priority(1b): 0x%02X (%u)\n”, p_header->transport_priority, p_header->transport_priority);

printf(” PID(13b): 0x%04X (%u)\n”, p_header->PID, p_header->PID);

printf(” transport_scrambling_control(2b): 0x%02X (%u) %s\n”, p_header->transport_scrambling_control, p_header->transport_scrambling_control, (p_header->transport_scrambling_control == 0x00 ? “(not scrambled)” : “(scrambled)”));

printf(” adaptation_field_control(2b): 0x%02X (%u) %s\n”, p_header->adaptation_field_control, p_header->adaptation_field_control, (p_header->adaptation_field_control == 0x00 ? “(no adap_field, no payload)” : p_header->adaptation_field_control == 0x01 ? “(no adap_field, payload only)” : p_header->adaptation_field_control == 0x10 ? “(adap_field only, no payload)” : “(adap_field followed by payload)”));

printf(” continuity_counter(4b): 0x%02X (%u)\n”, p_header->continuity_counter, p_header->continuity_counter);

}

结果:程序1:错误,程序2和3:正确。

原因分析:

主要分析点是程序1和程序3的区别,而程序2是一种繁琐但能保证正确性的实现方式,所以没有仔细分析程序2。

1.首先,考虑到可能是由于大小端的造成的,但是仔细分析后发现这是明显的单字节内数据错误问题,而大小端影响的是多字节的排列顺序。

2.其次,仔细分析了两种数据的结构的数据内存布局,发现是由于处理器定义字节的顺序是从右向左的,也就是说低位在最右边。如下图所示:

程序1的内存布局:当结构体位域成员不是字节对齐的时候,就出现了错误。

程序3的内存布局:使用倒序,巧妙地解决了处理器从右向左的访问顺序对程序造成的影响

总结:通过这次的问题,搞明白了3个概念,C语言的位域,大小端,处理器数据访问顺序。也掌握了一种更快速地解析数据包的方法