6

I'm so confused with sprintf that a funny problem with different platfrom. Code :

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;
}

The result in console (MSVC2010 debug/release): 64, 0

But the same code in console(CentOS64 gcc4.4.6): 64, 32

Any guy will help me, tks!

-------------updated--------------------------

Thanks guys. I have read this article: sprintf for unsigned _int64

Actually, PRIu64 in "inttypes.h" defined: I64uwhich is not supported on windows. So I can write like this:

sprintf(sql, "%I64u, %I32u", task_id, app_id);
Community
  • 1
  • 1
wells
  • 322
  • 1
  • 3
  • 8

6 Answers6

10

Use %llu format string for task_id in sprintf()as follows:

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

Edit: As @Simonc suggested its better to use: PRIu32 and PRIu64 macros defined in <inttypes.h> (as you have Linux tag) do like:

sprintf(sql, "%"PRIu64", %"PRIu32"", task_id, app_id);
//               ^           ^
//       for:   uint64_t    uint32_t  
Community
  • 1
  • 1
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • What has this to do with the actual print out: `64, 0`? – Andrejs Cainikovs Jun 12 '13 at 12:16
  • @GrijeshChauhan I don't think the `PRId32` is required. I think a format string of `"%"PRIu64", %u"` should be fine. Also, note that you'd want the macros for unsigned ints, so `PRIu64` (and likewise if you want to use the equivalent macro for the `uint32_t`). – simonc Jun 12 '13 at 12:28
  • @simonc yes it doesn't need its macro in `inttypes.h`. defined like `#define PRId32 "ld"` Thanks for the edit :) . – Grijesh Chauhan Jun 12 '13 at 12:32
  • On 32-bit machines task_id is long long unsigned int. Try to compile it with -Wextra option of gcc! – Claudio Jun 12 '13 at 12:37
  • @GrijeshChauhan, no, you don't need extra "" after PRId32, check-it with `cpp` or `gcc -E` – David Ranieri Jun 12 '13 at 12:39
  • @DavidRF Yes I have no extra `"`, that is what I have conversation in with simonc – Grijesh Chauhan Jun 12 '13 at 12:43
  • @Claudio you are possible correct but ` PRId64` will take care for this :) – Grijesh Chauhan Jun 12 '13 at 12:45
  • @DavidRF No problem David :), normally I do same mistakes. – Grijesh Chauhan Jun 12 '13 at 12:46
  • Down-vote are **wrong** because if `%u` correct for `uint32_t` (as OP says) then `%lu` is correct for `uint64_t`. Additionally I have given better technique. – Grijesh Chauhan Aug 16 '13 at 18:05
  • @GrijeshChauhan Why would %lu be correct ? On 32 bit linux, long is 32 bit. On 64 bit windows, long is 32 bit. On 64 bit linux, long is 64 bit, so it may work in that case, but that'd still be correct for only 1 of 3 platforms. – nos Aug 16 '13 at 18:07
  • Got it Read [this post](http://stackoverflow.com/questions/14073877/printf-and-llu-vs-lu-on-os-x) .. actually it is really hard to understand --Thanks! – Grijesh Chauhan Aug 16 '13 at 18:21
  • @JonathanLeffler Thanks very much to improve my answers, specially when I make English mistakes. I always notice edits in [revisions-history](http://stackoverflow.com/posts/17065245/revisions) made by you that help me to improve/learn tips. – Grijesh Chauhan Aug 16 '13 at 18:50
  • @Claudio I realized after reading few more posts and @ nos's commnet that `%lu` was wrong. I should have considered your suggestion carefully. Thanks! – Grijesh Chauhan Aug 16 '13 at 18:55
3

Format string %lu won't work on 32-bit machines, where a 64-bit variable is long long.

Use %llu for 64-bit instead:

#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;
}
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Claudio
  • 10,614
  • 4
  • 31
  • 71
  • 1
    Wrong. First of all, `ll` stands for `long long`, while you may want to use just `long`. Also, this has nothing to do with the actual print out: `64, 0`. – Andrejs Cainikovs Jun 12 '13 at 12:29
  • uint64 on linux does work as a long long. However, this won't address it on windows. a normal unsigned int is u, long is lu and long long is llu – fkl Jun 12 '13 at 12:31
  • On my 32-bit Linux machine gcc 4.7 complains if I use just %lu. The reason is that 64-bit unsigned int are long long. – Claudio Jun 12 '13 at 17:05
  • @AndrejsCainikovs If you use long, there are many real world platform it will not work on. long is not 64 bit on all platforms. long long is 64 bits on all current platforms that supports long long (though there's nothing wong with a platform implementing long long with > 64 bits, none do at the moment though) – nos Aug 16 '13 at 18:04
1

Just adding to what others have said:

Giving

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

instead of

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

gives an output 32, 64!!

No need to worry! Here is why: task_id is pushed to stack (higher 4 bytes first and lower 4 bytes second) before pushing app_id (as arguments to sprintf). But when sprintf goes to take arguments, it pops 4 bytes + 4 bytes from stack, as two %u are specified in the format. So it takes the lower 4 bytes of task_id and prints it as unsigned int.

The same happens when sprintf(sql, "%u, %u", task_id, app_id); is given.

app_id is pushed first and task_id next. But when sprintf reads, it pops two 4 bytes, 64 (the lower 4 bytes of task_id) and 00 (higher 4 byte of task_id and prints 64, 00.

raj raj
  • 1,932
  • 1
  • 14
  • 15
0

Try:

sprintf(sql, "%lu, %u", task_id, app_id);
jim mcnamara
  • 16,005
  • 2
  • 34
  • 51
0

As has been pointed out, the proper formatting specifier for uint64_t is PRIu64 (not lu, since there's no guarantee that uint64_t is long).

So, you need to use that:

#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);
legends2k
  • 31,634
  • 25
  • 118
  • 222
unwind
  • 391,730
  • 64
  • 469
  • 606
-1

The format specifier is wrong. The printf function doesn't know what kind of parameters are passed to it, it can only deduce this from the format specifiers. So when you pass a 64bit integer to it, and tell the function that you passed only a long (32bit) then it takes only half of the 64 bit value passed in. Depending on the architecture, the correct result might be printed or not. The reason is how the number is stored in memory and what the printf function sees when it reads the long value.

If the long value happens to have the same number of bits or the value is stored in memory in such a way that the expected result happens to be in the right place, the correct value could be printed, but of course, the code would still be wrong, though it appears to work.

Devolus
  • 21,661
  • 13
  • 66
  • 113