是否存在通用的方法:根据C结构定义改变数据的字节顺序?

fmddlmyy 2004-11-16 11:47:16
在嵌入式环境中,有些CPU核使用big-endian。它们产生的数据文件是big-endian的。
如果要在使用intel CPU的PC环境正确理解这些文件,就需要将big-endian转换为little-endian。

产生数据文件的程序在PC环境也可以运行,但在PC上产生的数据文件却是little-endian的。
如果要在嵌入式环境直接使用PC上产生的数据文件,就需要将little-endian转换为big-endian。

嵌入式环境的代码是用C写的,数据文件结构可以用一个庞大的C结构描述。
是否存在通用的方法,在PC环境,根据C结构定义改变数据的字节顺序?

因为在PC环境,所以在开发工具的选择上比较自由,任何C/C++的IDE,MC++,C++/CLI,perl都可以,但这种开发工具应该能理解C的头文件,

解决这个问题的最直接的方法就是对数据结构的每个元素编写改变字节顺序的代码。但当结构很庞大时,这种工作就是很繁琐、无聊的。我想在计算技术这么发达的时代,应该有自动处理的方法。

不知大家有什么好的想法?
...全文
137 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
fmddlmyy 2004-11-25
  • 打赏
  • 举报
回复
我要处理的问题比前面描述的还要复杂一些。简单地说:我要处理的数据文件在一个庞大结构的每个成员变量前硬加了一个字节,由于成员变量是8字节对齐的,所以额外的字节就破坏了整个结构的对齐关系。不过在Convert-Binary-C-0.56的帮助下,我还是写出了生成转换信息的脚本。脚本有140行,稍微复杂一些,但总算解决了原来可能要手工处理的问题。
我在刚开始考虑这个问题的时候,很自然地想到.net的反射。因为对.net不熟悉,同时也想了解一下其它编译环境是否有特殊的处理方法,所以发贴询问。谢谢大家参与。
fmddlmyy 2004-11-25
  • 打赏
  • 举报
回复
有时候,我们希望在C/C++程序里自动完成转换。
这是可以使用Convert-Binary-C-0.56编写脚本,自动分析需要转换的结构,生成转换信息:即由(偏移、大小)对组成的数组。然后用一个通用的函数就可以完成所有转换。例如:
typedef unsigned char uint8;
typedef struct {
short off;
short sz;
} SwapUnit;

void swap2(uint8 *p)
{
uint8 tmp;
tmp = p[0];
p[0] = p[1];
p[1] =tmp;
}

void swap4(uint8 *p)
{
uint8 tmp;
tmp = p[0];
p[0] = p[3];
p[3] =tmp;
tmp = p[1];
p[1] = p[2];
p[2] =tmp;
}

void swapx(uint8 *buf, SwapUnit *x, int cnt)
{
int i;
for (i = 0; i < cnt; i++) {
if ( x[i].sz == 2 ) {
swap2(&buf[x[i].off]);
}
else if ( x[i].sz == 4 ) {
swap4(&buf[x[i].off]);
}
}
}
这样,原来需要写几十个函数,现在只需要维护几十个数组。而这些数组是可以用脚本自动产生的。如果结构定义发生了变化。只要用脚本重新生成数据即可。
fmddlmyy 2004-11-25
  • 打赏
  • 举报
回复
我在CPAN找到了一个模块:Convert-Binary-C-0.56。
该模块具有编译器的预处理功能,可以获取C程序各种数据类型的定义信息。使用这个模块可以轻松改变一个结构的字节顺序。
例如以下脚本从文件big_endian.dat读入类型为big_struct_type的big-endian数据,转换为little-endian数据后输出到little_endian.dat。数据类型big_struct_type在文件sample.c中定义。

use Convert::Binary::C;

my $c = new Convert::Binary::C ByteOrder => 'BigEndian', Alignment => 8;
my @inc = ('D:/sample/include');
my @def = qw(SOME DEFINITIONS);
$c->configure( Include => \@inc,
Define => \@def );
$c->parse_file( 'sample.c' );
my $target = 'big_struct_type';

my $inputFile = 'big_endian.dat';
open(INFILE, "<$inputFile") or die "$inputFile could not be opened. \n";
binmode(INFILE);
my $data;
my @attr = stat(INFILE);
read(INFILE, $data, $attr[7]);
close(INFILE);

my $unpacked = $c->unpack( $target, $data );
$c->configure( ByteOrder => 'LittleEndian' );
$data = $c->pack( $target, $unpacked );

my $outputFile = 'little_endian.dat';
open(OUTFILE, ">$outputFile") or die "$outputFile could not be created. \n";
binmode(OUTFILE);
print OUTFILE $data;
close(OUTFILE);

在使用Convert::Binary::C分析C程序之前,可以自由选择编译需要的所有配置,例如包含路径、编译开关、字节对齐、结构对齐、字节顺序等等。
unpack从结构数据分解出每个元素的值。pack根据所有元素的值组装出结构数据。在组装之前,改变字节顺序的配置,就实现了字节顺序的改变。

fmddlmyy 2004-11-19
  • 打赏
  • 举报
回复
ntohl、ntohs只是转换一个4字节,或者2字节的数据。

我希望转换的是很多包含几十个成员的结构,其中很多成员又是结构,以此类推。另一方面,我看到的数据文件只是连续的字节流。
我写的程序必须通过分析源代码的结构定义,确定数据文件的哪些字节属于哪个元素,是byte、word、还是dword,然后再相应调整字节顺序。


evilch 2004-11-19
  • 打赏
  • 举报
回复
其实楼主可以用perl之类的些个脚本嘛。
自动生成该结构的转换的代码。
fmddlmyy 2004-11-19
  • 打赏
  • 举报
回复
我前面说"我看到的数据文件只是连续的字节流",是要表达:我看到的只是一堆字节,它们的结构信息必须分析相应的结构定义才能获取.

其实我们不仅要分析出哪两个字节属于一个word,哪四个字节属于一个dword,还要处理字节对齐问题,即跳过那些因对齐而引入的填充字节。
sharkhuang 2004-11-19
  • 打赏
  • 举报
回复
如果本生就是字节流没有必要转换。只有含有int等类型的需要转换
sharkhuang 2004-11-18
  • 打赏
  • 举报
回复
htonl
ntohl
Flood1984 2004-11-18
  • 打赏
  • 举报
回复
不懂啊
DeadWolf 2004-11-18
  • 打赏
  • 举报
回复
可以参考
ntohs 和ntohl
功能是把网络字节序转换为主机字节序
如果已经是主机字节序不做动作

  • 打赏
  • 举报
回复
一般定义文件格式的时候都是定义为网络字节序(Big-Endian)的.一般只有手工处理,没什么自动的办法.
yycec 2004-11-17
  • 打赏
  • 举报
回复
在不同的平台上使用相同的源程序,编译成不同平台的代码。不知能不能解决你的问题,帮你UP一下。

24,855

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧