C 用十六进制打印一个字符指针给了我奇怪的结果

C 用十六进制打印一个字符指针给了我奇怪的结果,c,C,所以我写了一个非常小和简单的程序,它把一个数字作为输入,转换成十六进制,然后一次打印出两个字符 对于某些数字,它会在输出前打印出ffffff 这是我的代码: //Convert the input to an unsigned int unsigned int a = strtoul (argv[1], NULL, 0); //Convert the unsigned int to a char pointer char* c = (char*) &a; //Print out

所以我写了一个非常小和简单的程序,它把一个数字作为输入,转换成十六进制,然后一次打印出两个字符

对于某些数字,它会在输出前打印出ffffff

这是我的代码:

    //Convert the input to an unsigned int
unsigned int a = strtoul (argv[1], NULL, 0);
//Convert the unsigned int to a char pointer
char* c = (char*) &a;

//Print out the char two at a time
for(int i = 0; i < 4; i++){
    printf("%02x ", c[i]);
}
但对于某些数字,输出如下所示:

./hex_int 1

01 00 00 00
./hex_int 100000

ffffffa0 ffffff86 01 00
如果你去掉所有的f,转换是正确的,但我不明白为什么它只在一些输入上这样做


有人有什么想法吗?

您的参数和打印格式不匹配。默认参数提升会导致您的
char
参数(
c[i]
)提升为
int
,符号扩展(显然您的
char
是有符号类型)。然后告诉
printf
使用
%x
格式将该参数解释为
无符号int
。繁荣-未定义的行为

使用:


相反。

char
默认情况下在您的系统上签名。将int移到其中会使编译器认为您希望在需要转换为int的操作上使用最高位作为符号位。将其打印为十六进制数就是其中之一

将字符指针
c
设置为
无符号字符*
,问题就会消失

如果Carl的评论是正确的(我将检查),请使用以下故障保护方法:

printf("%02x ", c[i] & 0xff);

我在那里做了一段时间,我意识到,你可以在一个进程中看到exe图像,使用调试程序,代码是正确的,但我暂时不能把这个机器代码传递给汇编程序,但是,好吧,有了指针一切都是可能的

include stdio.h

include windows.h

int main ()

{

int i=0;

char * p = (char *)0x400000;

for(int i = 0; i < 20; i++)

{

    printf("%p %02x \n",p+i, (unsigned int)(unsigned char)*(p+i));
}

}
包括stdio.h
包括windows.h
int main()
{
int i=0;
char*p=(char*)0x400000;
对于(int i=0;i<20;i++)
{
printf(“%p%02x\n”,p+i,(无符号整数)(无符号字符)*(p+i));
}
}

好吧,添加windows.h是为了使用一些系统调用,我在示例中省略了这些,因为下面的代码中没有必要使用这些,关于未签名,是的,可以使用,因为char总是>0,关于地址,正如您之前所说,0400000是exe的头,在这种情况下是“mz”头,但是进程的dll的代码可能是7c911000,dll的头可能是另一个地址,等等..,此信息在exe文件中,必须进行读取才能知道加载的映像在主内存中加载的位置,但是当您只有一个进程时,您会有更多,您必须使用系统调用来知道第二个进程在哪里,如果一个地址不可读,只需在记事本中读取de exe,该地址只是一个示例

可能的重复,而不是问题的原因,但因为
strtoul
返回一个
无符号长文件
,您可能应该将
a
声明为
unsigned long
,即使在您的处理器上,它的大小可能相同,也可能不同。@mbrach-为了一致性起见,这是个好主意,但可能不是严格必要的。从
unsigned long
unsigned int
的转换定义良好。@CarlNorum确实如此。我想我只是有点强迫症……我也意识到这个问题可以通过将c声明为无符号字符*而不仅仅是字符*来解决。感谢您的快速响应。使用
unsigned char
可能会得到正确的输出,但它仍然是未定义的行为。参数提升仍然是未修饰的
int
。直接转换为
unsigned int
将避免未定义的行为,但您仍然可能在负值
char
上获得
ffffff
“prefix”。好的,我将使用unsigned int。谢谢大家@查理贝利-那可能是真的。让我来解决这个问题。严格来说,使用
unsigned char*
仍然会导致print语句中出现未定义的行为。您所做的更改也没有解决这个问题。UB是由默认参数升级将该值转换为
int
,然后使用
%x
打印
无符号int
引起的。您的
也会发生同样的情况,因此需要
printf(“%02x”((int)c[i])&0xff)?(可能括号太多了,但现在我要破产了!)不,需要传递一个
无符号int
来匹配
%x
。使用
printf(“%02x”,(无符号int)c[i])
,假设
c
是一个
无符号字符*
。它肯定不是。“如果
int
可以表示原始类型的所有值(受宽度限制,对于位字段),则该值将转换为
int
。”
signed int
可以表示
无符号字符的所有值(即假定
sizeof(int)
>1)。未定义的行为仍然是未定义的,即使它碰巧给出了明显正确的结果。这与OP的问题有什么关系?P.S.1.
(unsigned int)
强制转换是不必要的。P.S.2.内存地址
0x400000
根本不能保证可读。是的,它可能通常在Windows x86中(因为您提到了
Windows.h
),但请注意,问题被标记为
C
,没有提及任何特定的操作系统或平台。回答问题之前,请阅读帮助页。这基本上是对你的答案的评论,而不是答案。另外,你的另一个答案也不在问题的范围内。什么?你读了线程的标题吗?用十六进制打印等,这是这里的主题,billg118打开这个线程,我正在发布和替代carl的代码,我没有做平行对话框或其他,我的答案在问题的范围内,因为我发布了代码,与其讨论问题,不如讨论主线,是否在本论坛讨论范围内?
include stdio.h

include windows.h

int main ()

{

int i=0;

char * p = (char *)0x400000;

for(int i = 0; i < 20; i++)

{

    printf("%p %02x \n",p+i, (unsigned int)(unsigned char)*(p+i));
}

}