2012-07-19 22 views
3

我试图从int中将字节转换为所有小端系统中的便携方式中的一系列字符。c中的移位字符

我有以下代码:

#include <stdio.h> 

int 
main() 
{ 
    int i = 0xabcdef12; 
    printf("i: %x\n", i); 
    char a, b, c, d; 
    a = (i >> 000) & 0xFF; 
    b = (i >> 010) & 0xFF; 
    c = (i >> 020) & 0xFF; 
    d = (i >> 030) & 0xFF; 
    printf("a b c d: %x %x %x %x\n", a , b, c, d); 
    if(a == 0x12) 
    printf("a is 0x12\n"); 
    if(b == 0xef) 
    printf("b is 0xef\n"); 
    if(c == 0xcd) 
    printf("c is 0xcd\n"); 
    if(d == 0xab) 
    printf("d is 0xab\n"); 
    if(a == 0xffffff12) 
    printf("a is 0x12\n"); 
    if(b == 0xffffffef) 
    printf("b is 0xffffffef\n"); 
    if(c == 0xffffffcd) 
    printf("c is 0xffffffcd\n"); 
    if(d == 0xffffffab) 
    printf("d is 0xffffffab\n"); 
    return 0; 
} 

这段代码使用-Wall编译时没有任何警告。

当运行此给出:

i: abcdef12 
a b c d: 12 ffffffef ffffffcd ffffffab 
a is 0x12 
b is 0xffffffef 
c is 0xffffffcd 
d is 0xffffffab 

这里有一些GCC打印:

Breakpoint 1, main() at test.c:14 
14 if(a == 0x12) 
(gdb) p/x a 
$1 = 0x12 
(gdb) p/x b 
$2 = 0xef 
(gdb) p/x c 
$3 = 0xcd 
(gdb) p/x d 
$4 = 0xab 

我敢肯定,我做错了什么。如果你可以回答以下几个问题,这将真正帮助我理解发生了什么:

  • char怎么能有大于0xff的值?
  • 什么不是& 0xff位掩码工作?
  • 为什么gdb报告正确的值?

如果任何人有一个可靠的(系统独立,但endianess并不重要)的方式从int到char [],这将是很好的。

+1

你有意使用八进制文字吗? – Mysticial 2012-07-19 00:32:17

+1

“如果有人从int到char []有一个可靠的(系统独立的,但是endianess并不重要),那将会很棒。” 关于工会呢? – 2012-07-19 00:35:22

+0

@ DennisMeng - 工会是键入指针的好方法。它们依赖于系统,但是...如果在四个无符号字符值的数组与一个整数之间进行联合,则可以非常方便地读出整数的字节;但是你的代码至少要依赖于计算机的字节顺序,也可能依赖于其他实现细节(你可能需要使用'#pragma'来控制填充)。我建议移植和屏蔽可移植代码,并且为应该尽可能快的代码添加联合加测试用例。 – steveha 2012-07-19 02:06:55

回答

5

这是一个快速修复。

变化:

char a, b, c, d; 

unsigned char a, b, c, d; 

的原因是char是您的系统上签字。当你通过a,b,c,d分成printf()时,他们被提升为int。他们是签名扩展的。这就是为什么你得到所有领先的ff

GDB正在报告正确的值,因为它正在直接读取chars。 (并且因此没有整数促销)

+1

有些人宁愿[只对无符号类型执行位移操作](https://www.securecoding.cert.org/confluence/display/seccode/INT13-C.+Use+bitwise+operators + only + on + unsigned +操作数)以避免必须考虑算术vs逻辑移位。从而避免了神秘指出的内容。 – 2012-07-19 00:40:17

+0

因此,'i'应该被做成'unsigned'。由于签名类型的右移在技术上是由实现定义的。 – Mysticial 2012-07-19 00:47:02

+0

谢谢,Prashant,我没有意识到有两种类型的转换。 (也没有想到0xffffffef不是一个庞大的数字,而是一个小的负数。) – rhlee 2012-07-19 11:30:08

1

在比较,abcd被晋升为int。由于它们都是char,所以最重要的位被视为符号位。升级到int将MSB填充到更高位。

0x12的MSB是0,和0xef0xcd0xab的最高位为1,这就是为什么升级后你0x000000120xffffffef0xffffffcd0xffffffab

如果更改

char a, b, c, d; 

unsigned char a, b, c, d; 

然后你就可以得到你所期望的。