C 将位字段转换为字节数组
我有一些mpeg ts位字段,例如传输流包:C 将位字段转换为字节数组,c,arrays,struct,unions,C,Arrays,Struct,Unions,我有一些mpeg ts位字段,例如传输流包: struct ts_package_header_s { 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
struct ts_package_header_s {
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;
};
struct ts_package_s {
struct ts_package_header_s ts_header;
unsigned char ts_body[TS_BODY];
};
union ts_package_u {
struct ts_package_s ts_package;
unsigned char bytes[TS_PACKAGE];
};
在我的源代码中,我初始化了头结构:
pat_package_header.sync_byte = 0x47;
pat_package_header.transport_error_indicator = 0;
pat_package_header.payload_unit_start_indicator = 1;
pat_package_header.transport_priority = 0;
pat_package_header.PID = PAT_PID;
pat_package_header.transport_scrambling_control = 0;
pat_package_header.adaptation_field_control = 1;
pat_package_header.continuity_counter = 0;
然后我把它做成了包装工会
union ts_package_u package;
package.ts_package.ts_header = pat_package_header;
然后我填充T_body数组。
当我将这个包写入文件时。我得到了一个数组:
10 00 40 47 XX XX XX.. instead of 47 40 10 00 XX XX XX..
我尝试将结构转换为char*,而不是使用union,但得到了相同的结果
故障在哪里?谢谢。像这样尝试将结构直接序列化到磁盘是很危险的,因为磁盘的格式必须在不同的体系结构中已知,或者使用不同的编译器 编译器在存储位字段的方式上有所不同,体系结构的基本端性也会改变数据的存储方式 例如,可能是编译器选择在字节、字或其他边界上对齐位字段。这是编译器的决定。它还可以选择以任何顺序保存位,这通常取决于您的机器的长度 为了安全地将此标头写入磁盘,您需要自己序列化数据。标头是32位的,根据 例如:
#include <stdio.h>
#define TS_BODY 1024
#define PAT_PID 0x40
struct ts_package_header_s {
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;
};
struct ts_package_s {
struct ts_package_header_s ts_header;
unsigned char ts_body[TS_BODY];
};
static void write_ts( struct ts_package_s pat_package )
{
FILE* f = fopen( "test.ts", "wb+" );
unsigned int header = 0;
if( f == NULL )
return;
header = pat_package.ts_header.sync_byte << 24;
header |= ( pat_package.ts_header.transport_error_indicator << 23 );
header |= ( pat_package.ts_header.payload_unit_start_indicator << 22 );
header |= ( pat_package.ts_header.transport_priority << 21 );
header |= ( pat_package.ts_header.PID << 8 );
header |= ( pat_package.ts_header.transport_scrambling_control << 6 );
header |= ( pat_package.ts_header.adaptation_field_control << 4 );
header |= ( pat_package.ts_header.continuity_counter );
/* Write the 32-bit header as big-endian */
unsigned char byte = header >> 24;
fwrite( &byte, 1, 1, f );
byte = ( header >> 16 ) & 0xFF;
fwrite( &byte, 1, 1, f );
byte = ( header >> 8 ) & 0xFF;
fwrite( &byte, 1, 1, f );
byte = header & 0xFF;
fwrite( &byte, 1, 1, f );
fclose( f );
}
int main( int argc, char* argv[] )
{
struct ts_package_s pat_package;
pat_package.ts_header.sync_byte = 0x47;
pat_package.ts_header.transport_error_indicator = 0;
pat_package.ts_header.payload_unit_start_indicator = 1;
pat_package.ts_header.transport_priority = 0;
pat_package.ts_header.PID = PAT_PID;
pat_package.ts_header.transport_scrambling_control = 0;
pat_package.ts_header.adaptation_field_control = 1;
pat_package.ts_header.continuity_counter = 0;
write_ts( pat_package );
return 0;
}
根据您使用的值,这似乎是正确的。使用类似的方法将结构直接序列化到磁盘是危险的,因为在磁盘上,不同的体系结构必须知道其格式,或者使用不同的编译器 编译器在存储位字段的方式上有所不同,体系结构的基本端性也会改变数据的存储方式 例如,可能是编译器选择在字节、字或其他边界上对齐位字段。这是编译器的决定。它还可以选择以任何顺序保存位,这通常取决于您的机器的长度 为了安全地将此标头写入磁盘,您需要自己序列化数据。标头是32位的,根据 例如:
#include <stdio.h>
#define TS_BODY 1024
#define PAT_PID 0x40
struct ts_package_header_s {
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;
};
struct ts_package_s {
struct ts_package_header_s ts_header;
unsigned char ts_body[TS_BODY];
};
static void write_ts( struct ts_package_s pat_package )
{
FILE* f = fopen( "test.ts", "wb+" );
unsigned int header = 0;
if( f == NULL )
return;
header = pat_package.ts_header.sync_byte << 24;
header |= ( pat_package.ts_header.transport_error_indicator << 23 );
header |= ( pat_package.ts_header.payload_unit_start_indicator << 22 );
header |= ( pat_package.ts_header.transport_priority << 21 );
header |= ( pat_package.ts_header.PID << 8 );
header |= ( pat_package.ts_header.transport_scrambling_control << 6 );
header |= ( pat_package.ts_header.adaptation_field_control << 4 );
header |= ( pat_package.ts_header.continuity_counter );
/* Write the 32-bit header as big-endian */
unsigned char byte = header >> 24;
fwrite( &byte, 1, 1, f );
byte = ( header >> 16 ) & 0xFF;
fwrite( &byte, 1, 1, f );
byte = ( header >> 8 ) & 0xFF;
fwrite( &byte, 1, 1, f );
byte = header & 0xFF;
fwrite( &byte, 1, 1, f );
fclose( f );
}
int main( int argc, char* argv[] )
{
struct ts_package_s pat_package;
pat_package.ts_header.sync_byte = 0x47;
pat_package.ts_header.transport_error_indicator = 0;
pat_package.ts_header.payload_unit_start_indicator = 1;
pat_package.ts_header.transport_priority = 0;
pat_package.ts_header.PID = PAT_PID;
pat_package.ts_header.transport_scrambling_control = 0;
pat_package.ts_header.adaptation_field_control = 1;
pat_package.ts_header.continuity_counter = 0;
write_ts( pat_package );
return 0;
}
根据您使用的值,它似乎是正确的。您已声明
sync_byte
为结构中的最后一个成员,现在您想知道它不是第一个成员。@mch如果我将此结构向后移动,我将得到“47 02 00 04”而不是“47 40 10 00”位字段没有可移植的表示形式,并且您的编译器可以随心所欲地布置它们。如果需要匹配现有的数据布局,不要使用位域。您已声明sync_byte
为结构中的最后一个成员,现在您想知道它不是第一个成员。@mch如果我将此结构向后移动,我将得到“47 02 00 04”而不是“47 40 10 00”位域,它没有可移植的表示形式,编译器可以随心所欲地排列它们。如果需要匹配现有的数据布局,请不要使用位字段。我们是否可以使用htonl()
将标头写入big-endian?我们是否可以使用htonl()
将标头写入big-endian?