22

I am having following code. output of second %d in sprintf is always shown as zero. I think i am specifying wrong specifiers. Can any one help me in getting write string with right values. And this has to achieved in posix standard. Thanks for inputs

void main() {
    unsigned _int64 dbFileSize = 99;
    unsigned _int64 fileSize = 100;
    char buf[128];
    memset(buf, 0x00, 128);
    sprintf(buf, "\nOD DB File Size = %d bytes \t XML file size = %d bytes", fileSize, dbFileSize);
    printf("The string is %s ", buf);
    }

Output:

The string is
OD DB File Size = 100 bytes      XML file size = 0 bytes 
hippietrail
  • 15,848
  • 18
  • 99
  • 158
venkysmarty
  • 11,099
  • 25
  • 101
  • 184

4 Answers4

19

You need to use %I64u with Visual C++.

However, on most C/C++ compiler, 64 bit integer is long long. Therefore, adopt to using long long and use %llu.

Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
19

I don't know what POSIX has to say about this, but this is nicely handled by core C99:

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint64_t dbFileSize = 99;
    uint64_t fileSize = 100;
    char buf[128];
    memset(buf, 0x00, 128);
    sprintf( buf, "\nOD DB File Size = %" PRIu64 " bytes \t"
                  " XML file size = %" PRIu64 " bytes\n"
                  , fileSize, dbFileSize );
    printf( "The string is %s\n", buf );
}

If your compiler isn't C99 compliant, get a different compiler. (Yes, I'm looking at you, Visual Studio.)

PS: If you are worried about portability, don't use %lld. That's for long long, but there are no guarantees that long long actually is the same as _int64 (POSIX) or int64_t (C99).

Edit: Mea culpa - I more or less brainlessly "search & replace"d the _int64 with int64_t without really looking at what I am doing. Thanks for the comments pointing out that it's uint64_t, not unsigned int64_t. Corrected.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 2
    You mean PRIu64 for unsigned? – Rup Feb 28 '11 at 10:52
  • 1
    You can portably use `%lld` if you cast the argument to `(long long int)` (or just `(long long)`) because no integer can be bigger than that. – Jim Balter Feb 28 '11 at 10:52
  • I think your code doesn't even compile, no? You can't prefix a `typedef` name by `unsigned`. The correct C99 `typedef` here would be `uint64_t`. Also using `memset` instead of just initializing the `buf` correctly is bad style, `char buf[128] = { 0 }` would do it. – Jens Gustedt Feb 28 '11 at 11:01
  • 1
    @Jim Balter: Implementations are at liberty to define additional types in the `intX_t` form, including but not limited to types bigger than 64 bit. There is no guarantee that `intmax_t` and `long long` are identical. – DevSolar Feb 28 '11 at 11:53
  • @Rup: @Jens Gustedt: You are right, of course. See updated answer. – DevSolar Feb 28 '11 at 11:54
  • @DevSolar type specifiers are listed in 6.7.2. intmax_t is defined in stdint.h. How might a type larger than long long be defined there? – Jim Balter Feb 28 '11 at 12:25
  • 1
    @Jim Balter: Yes, 6.7.2 lists the *required* types. But note that 7.1.3 reserves identifiers for the implementation, and both 7.8 and 7.18 allow for additional, *optional* types. An implementation might define `_Long128`, `int128_t` and `uint128_t` (plus the necessary print / scan macros in ``). But that is neither here nor there: *Assuming* that `long long` is 64bit is exactly the type of assumption that made generations of C programs break on major updates. – DevSolar Feb 28 '11 at 14:18
  • @DevSolar 6.7.2 lists the types, period. It includes typedef names, which of course include uint128_t etc. But the standard says what a legal typedef is. Regardless of what may have been intended, I don't believe it's possible for a conforming impl to have an int type bigger than unsigned long long. As for the assumption you mention, I didn't make it -- I said "if you cast" -- casting a uint64_t to (unsigned long long) only assumes the latter has *at least* 64 bits. And it doesn't even assume that -- it only assumes that the value being cast can fit. In practice, that's portable. – Jim Balter Mar 01 '11 at 01:35
  • @DevSolar P.S. Even if an implementation can, per the Standard, provide a uint64_t while at the same time making unsigned long long only 32 bits (which is what it would take to make %ull and a cast to (unsigned long long) fail in this case), that would fall under "quality of implementation" ... it would be a low quality one. There have been implementations of that sort that justify themselves via sophistic language lawyering (like saying its allowed for UD to set off nuclear war) but they fail in the marketplace. – Jim Balter Mar 01 '11 at 01:41
  • "If you are worried about portability" and C99 macros are not available, could use `uint64_t u64; sprintf( buf, "%llu", (unsigned long long) u64);` as `unsigned long long` is at _least_ 64 bits. – chux - Reinstate Monica Sep 15 '14 at 20:05
  • @chux: If you're worried about portability, and C99 macros are not available, get a proper compiler. ;-) (Yes, three years after this answer, three years after C++11 **officially** embraced those macros added to the C standard **fifteen** years ago, MSVC is **still** non-conforming. Put that in your pipe and smoke it.) – DevSolar Sep 16 '14 at 07:28
11

If you are looking for a portable solution, then use printf macros from <inttypes.h>. You may need to define __STDC_FORMAT_MACROS to make these available in C++.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 2
    Yes you **may** have to. The C standard says that the macro is needed for C++, and the C++0x draft says that you don't have to use it. Wonder which standard the header conforms to. :-) – Bo Persson Feb 28 '11 at 17:28
  • The more current one (C++0x). I'm wondering if the C committee will again make a new version of the C standard one year after the C++ standard comes out, just to spite them. :-\ – DevSolar Feb 28 '11 at 17:38
0

I would use sprintf_s with %dz and uint64_t, and promptly discover that I'm an idiot when I try it and find that %dz, the format specifier for an unsigned int, will work for uint32_t, which is good news, but it won't work for uint64_t. While I think Keith Thompson has already answered this adequately with regards to using PRIu64, one change I would make would be to use the buffer overrun safe versions sprintf_s and printf_s, another would be to (direct) initialize the char when it is declared, as suggested by Jens Gustedt;

#include <stdio.h>
#include <inttypes.h>

uint64_t dbFileSize = 99;
uint64_t fileSize = 100;
char buf[128]{ 0 };
sprintf_s(buf, "\nOD DB File Size = %" PRIu64 " bytes \t XML file size = %" PRIu64 " bytes\n", fileSize, dbFileSize);
printf_s("The string is %s ", buf);
Ben Weston
  • 65
  • 6
  • 2
    Don't say things like "but then I'm just a beginner, what do I know?". There's no reason to apologize for inexperience. Answer to the best of your ability, show references backing up your answer and explain why it's the best answer. I removed that, so now flesh out the answer. – the Tin Man Jan 19 '22 at 00:41