使用Intel编译器解决字节序问题

来源:互联网 发布:网络上的博客违法吗 编辑:程序博客网 时间:2024/05/02 18:34

使用Intel编译器解决字节序问题

1.       什么是字节序(Endianess)

Endian或者Endianess, 一般指的是在外部内存中存储的字节顺序。在IA平台上开发网络程序的程序员大多遇到过字节序问题。网络协议是按照大端字节序定义的, 我们通常称之为Big-endian, 简称大端。 IA架构的主机字节序是小端字节序, 我们称之为Little-endian, 简称小端。在主机上定义的数据比如IP地址在发送到网络端的时候, 通常需要做字节序的转换, 也就是小端到大端的转换, 比如使用HTON()来实现。

大端和小端在外部内存中存放的字节序是相反的。 对于大端来说, 在内存低地址存放的是数据高位字节,在内存高地址存放的是数据低位字节。 小端则相反, 在内存低地址存放的是数据低位字节, 在内存高位地址存放的是数据高位字节。

举例来说, 对于整数0x89ABCDEF在内存中的存放, 大端和小端区别如下图所示:

 

 

2.       大小端带来的程序移植问题

对于不同的主机架构, 支持的字节序也不一样。 对于英特尔的架构来说, 基本都是小端架构的。其他的比如sun SPARC, IBM PPC, 使用的是大端架构。如此一来, 针对某个架构开发的应用程序, 当我们要把它移植到其他不同字节序的架构上时, 就存在一个字节序的问题。 虽然同样是C/C++的代码, 同样一段程序, 在大端架构上执行得到的结果和小端架构上执行得到的结果可能是不一样的。

举个简单的例子, 程序foo.c

#include <stdio.h> 
    int a = 0x12345678;                                    
    int main()
    {
           char *ap = (char *) &a;
           printf("%2x %x\n", *ap, a); 
           return 0;
}

         上面程序中对整数a取地址后强制转换为字节指针, 然后把字节指针指向的字节打印出来。我们可以使用gcc来编译该程序, 无论大端还是小端平台, 使用命令gcc foo.c 编译该程序。

         在这个例子中, 在大端架构中, &a地址低位存放的是数据高位字节, 也就是0x12, 所以打印出来的值是0x12。 但是在小端架构中, 打印出来的数据值就是0x78了。 这样就导致了在不同的字节序平台上程序执行结果不一致, 从而出现程序的逻辑错误。

类似的例子有很多, 我们可以自己思考一下, 罗列一些在大小端平台上执行结果不一致的情况。

         对于很多针对SPARC 或者PPC开发的应用程序来说, 如果想把它移植到IA平台上, 字节序问题就是我们不得不考虑的一个问题。 特别是对一些传统的代码, 代码量大, 动则百万行, 千万行数量级的代码, 如果手工去修改这样的代码, 带来的工作量是相当巨大的。

 

3.       解决方案

针对字节序问题, 解决方案主要有2种, 手工修改代码和使用工具。

1.       手工修改。 该方案需要程序员扫描所有程序中可能出现字节序问题的地方, 逐点修改代码。 如果代码量小, 比如几千行的代码, 手工修改不失为一个较好的选择。 对于代码量大的情况, 手工修改工作量巨大, 字节问题定位困难, 容易产生遗漏, 调试难度高。 字节序的问题通常导致的是程序的逻辑错误, 一般都是运行时出错, 这样的问题对程序的调试带来不小的难度。

2.       使用Intel C/C++ Compiler with bi-endian technology来实现自动的字节序转换。

使用Intel编译器可以实现字节序的自动转换。 该编译器的实现大大节省了程序移植的难度, 极大的缩短了程序移植的工作量, 节省了程序移植的时间, 可以很快的帮助程序员移植大批量的代码到Intel平台上。对于百万或者千万行数量级的代码移植来说, 使用Intel编译器来实现代码的移植显然是一个最佳选择。

Intel编译器提供了很多种手段来帮助程序员实现代码的移植, 对字节序的控制从粗粒度的文件编译, 到细粒度的变量字节序, 均提供了很好的支持。 针对本文中提到的例子foo.c来说, 简单的用Intel编译器来编译: icc foo.c –big-endian

这样程序执行的结果就可以和期望的大端平台上执行结果完全一致。

Intel编译器针对字节序的支持内容有很多, 这里就不一一细述。 有兴趣的朋友可以跟我们联系。

 

相同程序在大端和小端平台上执行结果不一致的情况有很多, 有兴趣的朋友可以探讨一下。 这里再举个例子:

unsigned char a[2] = {1, 0};
short x;

x=*(short*)a;

 上面x的值在大端平台上和小端平台上值分别是什么呢?

大小端平台执行行为不一致的情况, 你还可以举出多少其他类型的例子呢?

 

原创粉丝点击