一个有趣的事情与sprintf

我很困惑sprintf,一个有趣的问题与不同的平台。 代码:

int main () { char sql[1024]; uint32_t app_id = 32; uint64_t task_id = 64; sprintf(sql, "%u, %u", task_id, app_id); printf ("%s\n", sql); return 0; } 

控制台(MSVC2010debugging/版本)中的结果:64,0

但是在控制台(CentOS64 gcc4.4.6)中的代码相同:64,32

任何人都会帮我的!

– – – – – – -更新 – – – – – – – – – – – – –

多谢你们。 我读过这篇文章: sprintf for unsigned _int64

实际上, "inttypes.h" I64u定义了: I64u不支持的I64u 。 所以我可以这样写:

 sprintf(sql, "%I64u, %I32u", task_id, app_id); 

sprintf()使用%llu格式字符串作为task_id ,如下所示:

 sprintf(sql, "%llu, %u", task_id, app_id); // ^ // for: long long unsigned int 

编辑:由于@ Simonc建议最好使用:在<inttypes.h>定义的PRIu32PRIu64宏(因为你有Linux标签)就像:

 sprintf(sql, "%"PRIu64", %"PRIu32"", task_id, app_id); // ^ ^ // for: uint64_t uint32_t 

格式化字符串%lu不适用于64位变量很long long 32位机器。

使用%llu替代64位:

 #include <stdio.h> #include <stdlib.h> #include <linux/types.h> #include <stdint.h> int main () { char sql[1024]; uint32_t app_id = 32; uint64_t task_id = 64; sprintf(sql, "%llu, %u", task_id, app_id); printf ("%s\n", sql); return 0; } 

尝试:

 sprintf(sql, "%lu, %u", task_id, app_id); 

正如已经指出的, uint64_t的正确的格式说明符是PRIu64不是 lu ,因为不能保证uint64_tlong )。

所以,你需要使用:

 #define __STDC_FORMAT_MACROS #include <inttypes.h> char sql[1024]; uint32_t app_id = 32; uint64_t task_id = 64; sprintf(sql, "%u, %" PRIu64, app_id, task_id); printf ("%s\n", sql); 

只是增加别人的话:

给予

 sprintf(sql, "%u, %u", app_id, task_id); 

代替

 sprintf(sql, "%u, %u", task_id, app_id); 

给出输出32, 64

不用担心! 这是为什么:在推送app_id (作为sprintf参数)之前, task_id被压入堆栈(高4字节,低4字节秒)。 但是当sprintf接受参数时,它会从堆栈中弹出4个字节+ 4个字节,因为在格式中指定了两个%u。 所以它需要task_id的低4个字节并将其打印为unsigned int

sprintf(sql, "%u, %u", task_id, app_id); 给出。

app_id推送task_id接下来推送task_id 。 但是当sprintf读取时,它弹出两个4字节, 64 (task_id的低4字节)和00 (高4字节的task_id并打印task_id

格式说明符是错误的。 printf函数不知道传递给它的是什么类型的参数,它只能从格式说明符中推导出来。 所以,当你传递一个64位的整数,并告诉函数,你只通过一个很长的(32位),那么只需要传入64位值的一半。根据架构,正确的结果可能会打印与否。 原因是数字如何存储在内存中,以及printf函数在读取long值时看到的是什么。

如果long值碰巧具有相同的比特数,或者将值存储在内存中,以致预期的结果恰好在正确的位置,则可以打印正确的值,但是当然,代码仍然会是错误的,尽管它似乎工作。