当我使用%u
在sprintf()
应用程序崩溃时,它与%d
工作良好
查看代码:
#include <stdio.h>
#include <string.h>
main()
{
unsigned char dAddr[4];
unsigned char sMask[4];
unsigned char nHop[4];
memset(dAddr,0,sizeof(dAddr));
memset(sMask,0,sizeof(sMask));
memset(nHop,0,sizeof(nHop));
unsigned int u4IpDAddr = 0x01020304;
unsigned int u4IpSNetMask = 0xffff01ff;
unsigned int u4NHopGt = 0x01020304;
char *dip = (char *)&u4IpDAddr;
char *smk = (char *)&u4IpSNetMask;
char *nhp = (char *)&u4NHopGt;
sprintf(dAddr, "%u.%u.%u.%u", dip[3], dip[2], dip[1], dip[0]); //if I used %d.%d.%d.%d its working fine
sprintf(sMask, "%u.%u.%u.%u", smk[3], smk[2], smk[1], smk[0]); //if I used %d.%d.%d.%d its working fine
sprintf(nHop, "%u.%u.%u.%u", nhp[3], nhp[2], nhp[1], nhp[0]); //if I used %d.%d.%d.%d its working fine
printf("SAM: func %s line %d IpDAddr %s Mask %s NHop %sn",__func__,__LINE__,dAddr,sMask,nHop);
}
当我用以下方式声明一个指针时,它的%u.%u.%u.%u
格式工作良好
unsigned char *dip = (unsigned char *)&u4IpDAddr;
unsigned char *smk = (unsigned char *)&u4IpSNetMask;
unsigned char *nhp = (unsigned char *)&u4NHopGt;
有谁能解释当我使用char
指针时发生了什么吗?
unsigned char dAddr[4];
unsigned char sMask[4];
unsigned char nHop[4];
不足以容纳字典学输出。
当你在sprintf()
中使用这些数组作为目标字符串时,本质上,你会超出分配的内存,创建未定义的行为。
您需要分配更多的内存来使用这些数组作为sprintf()
的目的地。
如果在您的平台上对char
进行了签名,那么您从u4IpSNetMask
中"破解"出来的char
值很可能是负的,因为您在u4IpSNetMask
中有以0xF...
开头的字节。当您将这样的char
值发送到sprintf
时,它们被转换为负int
值,然后由%u
说明符重新解释为unsigned
值。该行为实际上是未定义的- sprintf
负int
值与%u
是非法的。然而,在实践中,您通常会得到一个需要许多字符来表示的巨大正值。这些表示很容易溢出目标缓冲区,破坏程序堆栈并导致程序崩溃。
您可以自己看到sprintf
调用在典型平台上生成的内容:http://coliru.stacked-crooked.com/a/6aec03cfdf28f8b2
中间的sprintf
产生4294967295.4294967295.1.4294967295
。你期望这个怪物能适合只有4个字符长的缓冲区sMask
吗?
此外,同样的溢出也发生在%d
中,但是%d
产生的字符串表示更短(-1
代替4294967295
)并且损坏更小,这可能就是为什么程序在某种程度上跛行到最后而没有崩溃的原因。但这并没有改变字符串1.2.3.4
需要至少8个字符长的字符缓冲区的事实。你只提供了4.
换句话说,您的程序被%d
破坏了,就像被%u
破坏了一样。如果它没有崩溃与%d
,它只是出于随机运气。