在用C编写的微控制器项目中,我们定义了以下宏来访问多字节变量的不同字节(4字节long
):
#define BYTE_0(var) (*((unsigned char*) &var))
#define BYTE_1(var) (*(((unsigned char*) &var) + 1))
#define BYTE_2(var) (*(((unsigned char*) &var) + 2))
BYTE_0()
访问最低有效字节,依此类推。这是因为我们发现如果我们需要分别访问多字节变量的不同字节(8位微信息),使用上面的代码访问字节会在汇编中产生更少的代码行。由于代码存储器大小仅为15K,因此几个字节有时很宝贵。
我们使用的micro是little-endian。我想知道我们是否将代码移植到另一个是big-endian架构的微代码上面,上面的代码是否可行?换句话说,C标准是否保证(*((unsigned char*) &var))
将给出var
的最低有效字节?
答案 0 :(得分:4)
您的宏不起作用,它假设小端架构。在您的代码中,C标准不保证任何内容。与字节无关的代码通常使用逐位运算符编写,因为无论分配ls字节的位置如何,它们的行为方式都相同。
some_long & 0xFF
由C标准保证,无论字节顺序如何都会给出ls字节,而(uint8_t*)&some_long
依赖于字节序。
此链接详细解答了您的问题:http://www.ibm.com/developerworks/aix/library/au-endianc/ 使用按位移位和按位AND执行类似于清单12中的宏,并且它将是可移植的。
答案 1 :(得分:3)
不,这就是endianness的含义。您的代码不适用于具有相反字节顺序的计算机。
我甚至不确定这种手动优化是否重要。也许更好的编译器可以更好地优化......
答案 2 :(得分:2)
否
#define BYTE_0(var) (*((unsigned char*) &var))
会给你一个与处理器/内存控制器性质相关的字节,甚至不一定是变量var的一个字节。理想情况下,如果var为0x12345678,您希望在某些系统上看到0x12,在其他系统上看到0x78。
#define BYTE_0(var) (var&0xFF)
为任何系统提供var的最低有效字节 ASSUMING var在每个系统上都相同。
完成清单。
#define BYTE_0(var) ((var>> 0)&0xFF)
#define BYTE_1(var) ((var>> 8)&0xFF)
#define BYTE_2(var) ((var>> 16)&0xFF)
#define BYTE_3(var) ((var>> 24)&0xFF)
不要使用位域而不是移位和屏蔽,位域不会从编译器移植到编译器,端点相同或不同。位域是“实现定义的”,你能想到的每一个可能搞乱的东西都可以在编译器中找到。
小心试图扭转你的问题并从字节构建一个变量:
var = (b3<<24)|(b2<<16)|(b1<<8)|(b0<<0);
如果b3,b2,b1,b0被定义为8位变量,则编译器在移位之前不必将它们提升为32位。在某些系统/编译器上,上面的代码会产生将四个字节放入32位变量的预期效果。但是在其他系统中,var = b0就是上面的代码所要做的,因为b1是一个8位变量,它离开8,你留下零,同样转移b2 16和b3 24,你最终得到
var = 0 | 0 | 0 | b0;
我更喜欢
var = 0;
var <<= 8; var |= b3;
var <<= 8; var |= b2;
var <<= 8; var |= b1;
var <<= 8; var |= b0;
或
var = b3;
var <<= 8; var |= b2;
var <<= 8; var |= b1;
var <<= 8; var |= b0;
哪个端口相当不错。并且优化器应该为您提供与使用typedef或位域解决方案的单行C相似/相同的代码。
答案 3 :(得分:1)
不,不会。你已经明白为什么小端比大端更好地工作的原因。
还要考虑转换为不同的整数大小不需要任何指针算法。
假设long
总是4个字节也是错误的。不幸的是,x64的标准是LP64,即int
被遗忘为4字节整数。
答案 4 :(得分:0)
如果您想要一种可移植的方式来访问4字节整数的字节,您可以使用#define根据体系结构更改宏,
#ifdef LITTLE_ENDIAN
#define OFFSET_0 0
#define OFFSET_1 1
#define OFFSET_2 2
#else
#define OFFSET_0 3
#define OFFSET_1 2
#define OFFSET_2 1
#endif
#define BYTE_0(var) (*(((unsigned char*) &var) + OFFSET_0))
#define BYTE_1(var) (*(((unsigned char*) &var) + OFFSET_1))
#define BYTE_2(var) (*(((unsigned char*) &var) + OFFSET_2))
或者,如果你的架构支持超过1位的移位,这是最好的IMO。
#define BYTE_0(var) ((var) & 0xFF)
#define BYTE_1(var) (((var) >> 1 * CHAR_BIT) & 0xFF)
#define BYTE_2(var) (((var) >> 2 * CHAR_BIT) & 0xFF)
甚至适用于非lvars(例如表达式,文字的结果),并且是可移植的。