Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C中神秘的sprintf行为:第二个lld参数始终打印为零(0)_C_Printf - Fatal编程技术网

C中神秘的sprintf行为:第二个lld参数始终打印为零(0)

C中神秘的sprintf行为:第二个lld参数始终打印为零(0),c,printf,C,Printf,我在C语言中使用sprintf时遇到了一个完全奇怪的问题,这似乎超出了我的基本调试能力。基本上,我正在使用一个简单的单元测试框架(CuTest)向一个丑陋的(没有文档记录,没有单元测试)代码库添加一些测试。我添加了一种新类型的单元测试,它基本上复制了已经存在的单元测试,但代码中使用的64位整数除外 此测试通常有效(正确评估相等比较),但如果失败,由于sprintf问题,它不会生成正确的错误消息。函数如下所示: /* Comparison Function for U64 Numbers */ v

我在C语言中使用sprintf时遇到了一个完全奇怪的问题,这似乎超出了我的基本调试能力。基本上,我正在使用一个简单的单元测试框架(CuTest)向一个丑陋的(没有文档记录,没有单元测试)代码库添加一些测试。我添加了一种新类型的单元测试,它基本上复制了已经存在的单元测试,但代码中使用的64位整数除外

此测试通常有效(正确评估相等比较),但如果失败,由于sprintf问题,它不会生成正确的错误消息。函数如下所示:

/* Comparison Function for U64 Numbers */
void CuAssertU64Equals_LineMsg(CuTest* tc, const char* file, int line, const char* message, u64 expected, u64 actual) {
    char buf[STRING_MAX];
    if (expected == actual) return;
    sprintf(buf, "expected <%lld> but was <%lld>", expected, actual);
    CuFail_Line(tc, file, line, message, buf);
}
U64数字的比较函数*/ void CuAssertU64Equals_LineMsg(CuTest*tc,常量字符*文件,int行,常量字符*消息,预期为u64,实际为u64){ char buf[STRING_MAX]; 如果(预期==实际)返回; sprintf(buf,“预期的,但过去的”,预期的,实际的); CUU行(tc、文件、行、消息、buf); } (注意:字符串_MAX为512,因此应该足够大)。 (注2:在我目前使用的Cygwin系统上,u64是一个“long-long-int”变量)

当该测试失败时,产生的错误消息是奇怪的部分。不管“实际”的值是多少,它都会在该点打印0。因此,给定expected=1和actual=2,消息将是:

"expected <1> but was <0>"
“应为,但为”
如果切换参数的位置,并使其状态如下:

sprintf(buf, "actually <%lld> but expected <%lld>", actual, expected);
sprintf(buf,“实际但预期”,实际,预期);
您将获得以下输出:

"actually <2> but expected <0>"
“实际但预期”
不用说,这没有什么意义,似乎表明了某种奇怪的堆栈错误?老实说,我只是完全不清楚这种错误是如何发生的——即使在原则上也是如此。我用最可爱的代码制作了一个小的工作示例,它工作正常(没有将第二个设置为零)。这表明,既不是最可爱的,也不是功能本身的问题

但是,当与实际的代码库一起使用时,它会遇到这个问题。与环境(堆栈、内存或变量)相关的内容就是问题所在

有人知道为什么会发生这种情况吗?我目前的候选理论是: 1.尝试读取数据时,sprintf函数中出现下溢/溢出。但我不确定这将如何发生,因为传递到函数中的任何数据都是按值传递的。此外,数据本身显然存在——如果切换顺序,我可以看到每个值

  • 不知为什么,我使用了不正确的格式。我非常确定lld对于long-long int是正确的(并且在我的最小工作示例中有效),但它可能很脆弱

  • 某种类型的满栈损坏。当然希望不是这样,因为我一周只有20个小时在做这个项目。我怀疑我是否能够调试整个代码库来找出如此重要的东西

  • 我目前正在cygwin环境中使用gcc-3进行编译。任何猜测都很好,我知道在没有看到整个代码库的情况下,基本上不可能对其进行具体诊断,但即使是关于调试此类问题的一些线索也会很好。

    尝试将“%I64d”作为格式字符串。我不确定Cygwin,但我知道VisualStudio的标准库中printf函数中的MinGW链接造成了各种破坏。小心任何新的C99功能和类型,如长双精度或大小\u t格式

    值得一提的是,在这种情况下,这里有一个printf的替代品:

    static char *CuPrintU64(char* buffer, u64 value) {
        do
            *--buffer = value % 10 + '0';
        while(value /= 10);
        return buffer;
    }
    
    /* Comparison Function for U64 Numbers */
    void CuAssertU64Equals_LineMsg(CuTest* tc, const char* file, int line, const char* message, u64 expected, u64 actual) {
        static const char first[] = "expected ";
        static const char second[] = " but was ";
    
        char buf[STRING_MAX], *ptr = &buf[sizeof buf];
    
        if(expected == actual) return;
    
        /* sprintf(buf, "expected <%llu> but was <%llu>", expected, actual); */
        *--ptr = '\0';
        ptr = CuPrintU64(ptr, actual);
        ptr = memcpy(ptr - second, sizeof second - 1);
        ptr = CuPrintU64(ptr, expected);
        ptr = memcpy(ptr - first, sizeof first - 1);
    
        CuFail_Line(tc, file, line, message, ptr);
    }
    
    static char*CuPrintU64(char*buffer,u64值){
    做
    *--缓冲区=值%10+“0”;
    而(值/=10);
    返回缓冲区;
    }
    /*U64数字的比较函数*/
    void CuAssertU64Equals_LineMsg(CuTest*tc,常量字符*文件,int行,常量字符*消息,预期为u64,实际为u64){
    静态常量char first[]=“应为”;
    static const char second[]=“but was”;
    char buf[STRING_MAX],*ptr=&buf[sizeof buf];
    如果(预期==实际)返回;
    /*sprintf(buf,“预期的,但过去的”,预期的,实际的)*/
    *--ptr='\0';
    ptr=CuPrintU64(ptr,实际值);
    ptr=memcpy(ptr-second,sizeof second-1);
    ptr=铜64(预期为ptr);
    ptr=memcpy(ptr-first,sizeof-first-1);
    CuFail_行(tc、文件、行、消息、ptr);
    }
    
    这太奇怪了。我建议在valgrind下运行该程序,看看是否会出现内存错误。我应该注意,我已经找到了u64数据类型的定义位置,并且它肯定是一个长整型,至少在Cygwin下编译时是这样的(代码有一组编译器ifdef,可以根据不同的操作系统对其进行调整)。有人会认为它是一个无符号的值,但它实际上是有符号的(考虑到代码中一些非常奇怪的命名选择,这并不奇怪)?如前所述,这个问题只在使用大量代码库时才会出现,我认为没有人想要10页长的编译器日志?相关文件没有显示我能看到的任何值得注意的内容,没有警告或类似的内容。尝试显式地显示,但在此编译器模式下它根本无法识别格式(字面上写为“I64d”)。谢谢你在这里扔东西。至少是一个有趣的解决方案。现在我的解决方法实际上是执行两个单独的sprintf语句来分离缓冲区,然后组合缓冲区(这很好)。不过,如果第一部分开始出现故障,这绝对是一种有用的方法。@Namey我怀疑您会发现
    %lld
    实际上被视为
    %ld
    ,并且只读取64位整数的一半,所以这不是一个很好的解决方法(特别是如果您希望打印任何大于
    LONG_MAX
    )的数字。如果您不希望打印任何如此大的值,更好的解决方案可能是使用
    %lu
    并强制转换va