【问题标题】:Problem with sprintf function, last parameters are wrong when writtensprintf函数有问题,最后一个参数写错了
【发布时间】:2010-02-19 21:15:50
【问题描述】:

所以我使用 sprintf

sprintf(buffer, "%f|%f|%f|%f|%f|%f|%d|%f|%d", x, y, z, u, v, w, nID, dDistance, nConfig);

但是当我打印缓冲区时,我得到最后两个参数错误,假设它们是 35.0000 和 0,在字符串中它们是 0.00000 和 10332430,我的缓冲区足够长,所有其他参数在字符串

有什么想法吗? sprintf 有长度限制吗?

我检查了所有数字的类型,它们是正确的,但问题似乎是 dDistance。当我从 sprint 中删除它时,nConfig 会在字符串中获得正确的值,但是当我删除 nConfig 时,dDistance 仍然没有获得正确的值。我查了一下,dDistance 是双倍的。有什么想法吗?

因为人们似乎不相信我,所以我这样做了:

char test[255]={0};
int test1 = 2;
double test2=35.00;
int test3 = 0;

sprintf(test,"%d|%f|%d",test1,test2,test3);

我在我的字符串中得到了这个:

2|0.000000|1078034432

【问题讨论】:

  • 抱歉,您检查过这些值是否正确吗?
  • 很难评论。发布重现此问题的最小可编译源。至少,尝试在控制台上打印这些值。检查sprintf的返回值。
  • 如果您尝试 sprintf 仅输出最后两个参数会怎样?
  • x,y,z等有哪些类型?
  • 为什么不在调试器中单步执行对 sprintf 的调用,看看它在做什么?这有点乏味,但结果通常很有启发性。

标签: c++ c printf


【解决方案1】:

我会检查以确保您的参数类型与您的格式字符串元素匹配。尝试将 double 显示为整数类型 (%d) 或反之亦然会产生奇怪的输出。

【讨论】:

    【解决方案2】:

    您确定您的数据类型符合您的格式规范吗?

    尝试打印出你的数据,也就是创建一个相同格式的 printf,看看会发生什么:

    printf("%f|%f|%f|%f|%f|%f|%d|%f|%d", x, y, z, u, v, w, nID,dDistance, nConfig);
    

    尝试使用流,例如

    stringstream ss;
    
    ss << x << "|" << y << "|" << z << "|" << u << "|" << v << "|" << w << "|"
       << nID << "|"<< dDistance << "|"<< nConfig;
    
    string s = ss.str();
    

    然后用 s 做点什么;

    【讨论】:

    • 它们匹配但是当我尝试交换时让我们说第一个与最后一个交换 %f 与 %d 以及我得到正确的字符串。
    • 我不明白你的意思,请进一步解释?
    • 如果我将 x 与 nconfig 交换并将 %f 和 %d 放在各自的位置,我会得到正确的字符串。
    • 你是说这个说法有效吗? printf("%d|%f|%f|%f|%f|%f|%d|%f|%f", nConfig, y, z, u, v, w, nID,dDistance, x);因为 /that/ 听起来像是你在某处打错字了
    【解决方案3】:

    long 和 int 的大小是多少?

    如果 nID 以 'int' 格式和 sizeof(int) != sizeof(long) 长时间打印,则从那里开始您将获得未对齐的数据访问(从某种意义上说,对齐不正确)。

    您使用的是哪个编译器?如果这是问题所在,GCC 应该毫无困难地诊断问题。同样,如果 nID 是“long long”,您可能会遇到问题。


    回答您的问题 - 是的,sprintf() 必须能够处理的字符串长度的上限有一个下限。 C89 系统为 509,C99 系统为 4095。

    准确地说,C99 说(fprintf(),第 7.19.6.1 节,第 15 段):

    任何一次转换可以产生的字符数至少应为 4095.

    sprintf() 没有进一步的限定。


    将修改后的示例的固定版本转换为可编译代码:

    #include <stdio.h>
    int main(void)
    {
        char  test[255] = {0};
        int    test1 = 2;
        double test2 = 35.00;
        int    test3 = 0;
        sprintf(test, "%d|%f|%d", test1, test2, test3);
        puts(test);
        return(0);
    }
    

    我得到了我期望的输出:

    2|35.000000|0
    

    要获得显示的输出,您必须使用非常奇怪的设置。

    • 你在哪个平台上?

    您所显示的行为表明您正在使用的sprintf() 函数对某些内容的对齐方式或大小感到困惑。您是否有范围内的原型 - 也就是说,您是否已#included &lt;stdio.h&gt;?使用 GCC,当我省略标题时会收到各种警告:

    x.c: In function ‘main’:
    x.c:8: warning: implicit declaration of function ‘sprintf’
    x.c:8: warning: incompatible implicit declaration of built-in function ‘sprintf’
    x.c:9: warning: implicit declaration of function ‘puts’
    

    但即使将test2 重新定义为float,我也会得到正确的结果。

    如果我将test2 更改为long double,则会收到一组不同的警告和不同的结果:

    x.c: In function ‘main’:
    x.c:8: warning: implicit declaration of function ‘sprintf’
    x.c:8: warning: incompatible implicit declaration of built-in function ‘sprintf’
    x.c:8: warning: format ‘%f’ expects type ‘double’, but argument 4 has type ‘long double’
    x.c:9: warning: implicit declaration of function ‘puts’
    
    2|0.000000|0
    

    这与您所看到的更接近,但远非完全相同。

    由于我们没有平台信息,我怀疑您正在使用真正古老的(或者我的意思是错误的?)C 版本。但我仍然不知道如何你得到你所展示的 - 除非你在一个大端机器上(我正在使用 MacOS X 10.6.2 的 Intel Mac 上测试)......暂停......在 SPARC 机器上运行Solaris 10,没有#include &lt;stdio.h&gt;long double test2 = 35.0;,我得到:

    gcc -O x.c -o x && ./x 
    x.c: In function 'main':
    x.c:8: warning: incompatible implicit declaration of built-in function 'sprintf'
    2|-22446048024026502740613283801712842727785152907992454451420278635613183447049251888877319095301502091725503415850736723945766334416305449970423980980099172087880564051243997662107950451281495566975073444407658980167407319222477077473080454782593800009947058951029590025152409694784570786541673131117073399808.000000|0
    

    那不一样;它还会生成 321 个字符的输出,因此那里存在缓冲区溢出 - 最好使用“snprintf()”来防止这种情况发生。当事情被正确声明时,当然,我得到了预期的结果。

    那么,您可以发布显示您的问题的可编译代码,而不是不显示问题的 sn-p 吗?你能确定你的平台——机器类型、操作系统版本、编译器版本(可能还有 C 库版本)吗?

    【讨论】:

      【解决方案4】:

      dDistance 类型是 double 吗?看起来你的 %f 只抓取了一个 double 的四个字节,然后接下来的四个字节被视为一个整数,然后忽略真正的整数值。

      这个问题被标记为 C++;你能使用 std::ostringstream 来消除转换字符串的任何可能问题吗?

      【讨论】:

      • 除了 nID 和 nConfig 是 int 之外,一切都是双精度数。
      • 从您的最新更新中,如果您将 35.0 转换为 IEEE double,您将获得位模式 0x107803443200000000。如果只取前四个字节,它恰好以整数形式转换为 1078034432(这仅适用于您的体系结构是小端序的情况)。在您的测试程序中尝试 %lf 而不是 %f 以查看您的库是否可能未正确处理 %f-to-double 格式。
      猜你喜欢
      • 1970-01-01
      • 2020-03-30
      • 2020-11-24
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      • 2021-06-25
      • 1970-01-01
      • 2018-05-10
      相关资源
      最近更新 更多