当我在%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 %s\n",__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
指针时,任何人都可以解释发生了什么吗?
答案 0 :(得分:9)
在你的情况下
unsigned char dAddr[4];
unsigned char sMask[4];
unsigned char nHop[4];
不足以保存词典输出。
当您在sprintf()
中使用这些数组作为目标字符串时,基本上,您将超出分配的内存,创建undefined behaviour。
您需要分配更多内存才能将这些数组用作sprintf()
的目标。
答案 1 :(得分:1)
如果在您的平台上签署了char
,那么char
就会重视您已经解决的问题&#34;您的u4IpSNetMask
很可能是否定的,因为您在0xF...
中的字节以u4IpSNetMask
开头。当您将此类char
值发送至sprintf
时,它们会转换为负int
值,然后由unsigned
说明符重新解释为%u
值。该行为实际上是未定义的 - 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
崩溃,那只是随机运气。