Printf()将字符打印为32位数

5

我正在进行一个快速测试,以确保我对指针算术有所了解:

main.c

#include <stdio.h>
#include <stdlib.h>

#define ADDRESS    0xC0DCA11501LL
#define LENGTH     5


void print_address( char *, char );

/* Main program */
int main( int argc, char *argv[] )
{
    char nums[ LENGTH ];

    /* LSB first */
    for( int i = 0; i < LENGTH; i++ )
    {
        nums[ i ] = ( ADDRESS >> ( 8 * i ) ) & 0xFF;
    }

    print_address( nums, LENGTH );

    system("PAUSE");

    return 0;
}

void print_address( char *data, char len )
{
     char *data_ptr = data;

     while( len-- )
     {
            printf( "%X\n", *data_ptr++ );
     }
}

我的期望是以十六进制格式输出ADDRESS的字节,最低有效位(LSB)先输出。但是最后三个字节似乎以32位长度打印出来:

1
15
FFFFFFA1
FFFFFFDC
FFFFFFC0
Press any key to continue . . .

这是因为我的位移算术、某些编译器特定的问题还是printf()的行为导致的吗?

(我使用的是MinGW GCC v6.3.0在Windows 10上进行编译。)


3
打赌那个字符是有符号值,并且你看到FFFF是因为A1大于0x80并以有符号形式显示。尝试使用无符号字符指针。 - Michael Dorgan
1
@MichaelDorgan 哎呀!你说得对——将A、D和C改为7就让它消失了。 - calcium3000
我会简单回答。 - Michael Dorgan
1
还有,0xC0DCA11501LL 应该改为 0xC0DCA11501ULL。对有符号整数进行移位操作是未定义的行为。 - Jean-François Fabre
将负有符号整数进行移位是未定义的。移位正有符号整数是实现定义的。尽管如此,在这些情况下,无符号整数是更好的选择,原因有很多。 - Michael Dorgan
还要在nums数组中使用无符号字符。 - Michael Dorgan
3个回答

5

我认为您的char被用作有符号值,并且您看到FFFF是因为0xA1大于0x80,因此显示为带符号。尝试使用无符号char指针(对于nums数组和函数原型中的data),问题应该就消失了。


1
我猜 "Betcha" 是 "I bet that" 的俚语。我的猜测正确吗? - machine_1
是的 - 抱歉使用了俚语。Betcha 是 I bet that 的缩写。 - Michael Dorgan
请编译它并让我知道它的工作原理。因为那也是我的第一个猜测,但对我来说没有起作用。如果它能工作,我会删除我的答案。如果它不能工作,请给我的答案点赞 :-) - Jose Manuel Gomez Alvarez

2

您的环境中 char 类型似乎是有符号的,因此 8 位值 A1 实际上表示一个负数。请注意,printfvarargs 将被提升为 int 类型,并且一个负数将填充前导 1 位。换句话说,有符号的 A1 在提升为 32 位整数时将得到 FFFFFFA1。这就是原因。

请改用 unsigned char

void print_address( unsigned char *, char );

/* Main program */
int main( int argc, char *argv[] )
{
    unsigned char nums[ LENGTH ];

    /* LSB first */
    for( int i = 0; i < LENGTH; i++ )
    {
        nums[ i ] = ( ADDRESS >> ( 8 * i ) ) & 0xFF;
    }

    print_address( nums, LENGTH );

    system("PAUSE");

    return 0;
}

void print_address( unsigned char *data, char len )
{
    unsigned char *data_ptr = data;

    while( len-- )
    {
        printf( "%X\n", *data_ptr++ );
    }
}

0
问题是printf不知道你的数据类型是char。 试试这个。
void print_address( char *data, char len )
{
     char *data_ptr = data;

     while( len-- )
     {
            printf( "%02X\n", *data_ptr++ &0xFF);
     }
}

结果:

[jmgomez@d1 tmp]$ a.o
01
15
A1
DC
C0
sh: PAUSE: command not found
[jmgomez@d1 tmp]$

1
虽然这个方法能够达到效果,但它是通过截断来掩盖有符号/无符号的问题。最好在进行字节操作时使用无符号以预防问题的发生。 - Michael Dorgan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接