cross-platform printing of 64-bit integers with printf - c

In Windows, it is "%I64d". In Linux and Solaris, it is "%lld".
If I want to write cross-platform printfs that prints long long values: what is good way of doing so ?
long long ll;
printf(???, ll);

There are a couple of approaches.
You could write your code in C99-conforming fashion, and then supply system-specific hacks when the compiler-writers let you down. (Sadly, that's rather common in C99.)
#include <stdint.h>
#include <inttypes.h>
printf("My value is %10" PRId64 "\n", some_64_bit_expression);
If one of your target systems has neglected to implement <inttypes.h> or has in some other way fiendishly slacked off because some of the type features are optional, then you just need a system-specific #define for PRId64 (or whatever) on that system.
The other approach is to pick something that's currently always implemented as 64-bits and is supported by printf, and then cast. Not perfect but it will often do:
printf("My value is %10lld\n", (long long)some_64_bit_expression);

MSVC supports long long and ll starting Visual Studio 2005.
You could check the value of the _MSC_VER macro (>= 1400 for 2005), or simply don't support older compilers.
It doesn't provide the C99 macros, so you will have to cast to long long rather than using PRId64.
This won't help if you're using older MSVC libraries with a non-MSVC compiler (I think mingw, at least, provides its own version of printf that supports ll)

No on linux and solaris it is only incidentally that this is lld for a 64bit type. C99 prescribes simple (but ugly) macros to make these things portable PRId64. Since some windows compilers don't follow the standard you might be out of luck, there, unfortunately.
Edit: In your example you are using a different thing than a 64bit integer, namely a long long. This could well be 128 on some architectures. Here C99 has typedefs that guarantee you the minimum or exact width of the type (if they are implemented on the platform). These types are found with the inttypes.h header, namely int64_t for a fixe-width 64 bit type represented in two's complement. Maybe or maybe not your windows compiler has this.

As alternative you can use code like this:
uint64_t currentTimeMs = ...;
printf("currentTimeMs = 0x%08x%08x\n",
(uint32_t)(currentTimeMs >> 32),
(uint32_t)(currentTimeMs & 0xFFFFFFFF)
);
Or maybe:
printf("currentTimeMs = %u%09u\n",
(uint32_t)(currentTimeMs / 1000000000),
(uint32_t)(currentTimeMs % 1000000000)
);

Related

How to detect if printf will support %a?

I need to losslessly represent a double precision float in a string, and so I am using
sprintf(buf, "%la", x);
This works fine on my system, but when built on MinGW under Windows, gives a warning:
unknown conversion type character 'a' in format
I coded up a workaround for this case, but have trouble detecting when I should use the workaround -- I tried #if __STDC_VERSION__ >= 199901L, but it seems Gcc/MinGW defines that even if it doesn't support %a. Is there another macro I could check?
This doesn't answer the question "How to detect if printf will support %a?" in the general case, but you can modify your compiler installation so that %a is supported.
First of all , use mingw-w64. This is an up-to-date fork of MinGW. The original version of MinGW is not well maintained and does not fix bugs such as you are experiencing (preferring to blame Microsoft or something).
Using mingw-w64 4.9.2 in Windows 10, the following code works for me:
#include <stdio.h>
int main()
{
double x = 3.14;
printf("%a\n", x);
}
producing 0x1.91eb85p+1 which is correct. This is still deferring to the Microsoft runtime.
Your question mentions %la, however %a and %la are both the same and can be used to print either a float or a double argument.
If you want to print a long double, then the Microsoft runtime does not support that; gcc and MS use different sizes of long double. You have to use mingw-w64's own printf implementation:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
int main()
{
long double x = 3.14;
printf("%La\n", x);
}
which outputs 0xc.8f5c28f5c28f8p-2. This is actually the same number as 0x1.91eb85p+1 with more precision and a different placement of the binary point, it is also correct.
As jxh already suspected, MingW uses the MSVCRT LibC from Windows. The C99 support is not complete, especially some of the options of printf(3) like a are missing.

Is there a way to fix format specifiers warnings for stdint types?

The problem is that on one platform (windows, mvsc2015) uint64_t is defined as unsigned long long and on another (ubuntu, clang) it's unsigned long and there is the code which looks like
sprintf(buffer, "%#llx", u64key);
The solution is to use C99's format macros, in particular PRIu64 for an uint64_t:
#include <inttypes.h>
…
sprintf(buffer, "%#" PRIu64 "\n", u64key);
Pascal's solution is the most direct and most idiomatic for this particular type, but for the record, an alternative for printing arbitrary integer types whose definitions you don't know is simply casting to intmax_t or uintmax_t then using the j modifier (e.g. %jd or %ju). This might not work on most/all versions of MSVC's standard library implementation, however, because they're way behind on standards conformance.
You could use preprocessor directives to detect how a datatype is defined and compile another sprintf() with a different string.

Is u_int64_t available on 32-bit machine?

I want to use a u_int64_t variable as search key.
Is u_int64_t available on 32-bit machine?
If not, do I have to divide this variable into two variables? Then as a search key, it is a bit more troublesome.
Are there any workarounds for this?
An unsigned 64-bit integral type is not guaranteed by the C standard, but is typically available on 32-bit machines, and on virtually all machines running Linux. When present, the type will be named uint64_t (note one less underscore) and declared in the <stdint.h> header file.
Yes 64 bit integer datatype is supported on a 32 bit machine.
In C89 Standard , long long (≥ 64, ≥ size of long) type is supported as a GNU extension.
In C99 standard, there is native support for long long(≥ 64, ≥ size of long) integer.
as per some of the documentation or reading its not quite clear
__GLIBC_HAVE_LONG_LONG is the one that defines its presense in 32 bit architecture
aprobable solution for usage could be something similar to below
#include <sys/types.h>
#ifdef __GLIBC_HAVE_LONG_LONG
u_int64_t i;
#endif
Oh bythe way this is in linux

long integer problem

I'm a beginner at C, and using Turbo C++ compiler (16 bit).
In the software I'm writing, the maximum answer is around 32000. If I want a number larger than that, I use long int.
If I execute the following program:
#include <stdio.h>
void main()
{
long int x;
x=40000;
printf("%d", x);
}
Then I get an error that the constant value is long in function main().
How can I get an answer more that 32000 and get rid of this error?
also nw i change %d to %ld and use 40000L bt when i use unsigned integer then also i need to use 'l' with 40000//??
Use %ld in printf for the long int. %d is for int which only has 16 bits in your compiler. And for the error message, use x=40000L.
Change long to unsigned, 40000 will fit in unsigned int.
Assuming you're on windows, the best solution to this is to target a 32 or 64-bit platform. 16-bit programs won't even run on 64-bit versions of windows; you should really upgrade.
Microsoft has a free version of Visual Studio: Visual C++ Express Edition. This is an excellent option also because it comes with a full IDE.
Gcc is also available for windows in the form of Mingw. Unfortunately, mingw itself does not release ready-to-use compilers, but others do, such as equation.com or TDM.
Perhaps brushing up on variadic formatting might help :) By the time you (or the printf() subsystem) actually gets to expanding variadic arguments, its assumed that you know what type they are.
This not only goes for printf, but any other function that employs va_*() or v*printf() when discussing printf. Don't lose track of your types.
Also, keep track of signedness to avoid unexpected results.
In other words, by the time you call printf(), or anything else accepting an elipsis, be sure of what you are passing. This isn't limited to printf(), in fact venturing beyond that will often not produce compiler warnings.

How to Declare a 32-bit Integer in C

What's the best way to declare an integer type which is always 4 byte on any platforms? I don't worry about certain device or old machines which has 16-bit int.
#include <stdint.h>
int32_t my_32bit_int;
C doesn't concern itself very much with exact sizes of integer types, C99 introduces the header stdint.h , which is probably your best bet. Include that and you can use e.g. int32_t. Of course not all platforms might support that.
Corey's answer is correct for "best", in my opinion, but a simple "int" will also work in practice (given that you're ignoring systems with 16-bit int). At this point, so much code depends on int being 32-bit that system vendors aren't going to change it.
(See also why long is 32-bit on lots of 64-bit systems and why we have "long long".)
One of the benefits of using int32_t, though, is that you're not perpetuating this problem!
You could hunt down a copy of Brian Gladman's brg_types.h if you don't have stdint.h.
brg_types.h will discover the sizes of the various integers on your platform and will create typedefs for the common sizes: 8, 16, 32 and 64 bits.
You need to include inttypes.h instead of stdint.h because stdint.h is not available on some platforms such as Solaris, and inttypes.h will include stdint.h for you on systems such as Linux.
If you include inttypes.h then your code is more portable between Linux and Solaris.
This link explains what I'm saying:
HP link about inttypes.h
And this link has a table showing why you don't want to use long or int if you have an intention of a certain number of bits being present in your data type.
IBM link about portable data types
C99 or later
Use <stdint.h>.
If your implementation supports 2's complement 32-bit integers then it must define int32_t.
If not then the next best thing is int_least32_t which is an integer type supported by the implementation that is at least 32 bits, regardless of representation (two's complement, one's complement, etc.).
There is also int_fast32_t which is an integer type at least 32-bits wide, chosen with the intention of allowing the fastest operations for that size requirement.
ANSI C
You can use long, which is guaranteed to be at least 32-bits wide as a result of the minimum range requirements specified by the standard.
If you would rather use the smallest integer type to fit a 32-bit number, then you can use preprocessor statements like the following with the macros defined in <limits.h>:
#define TARGET_MAX 2147483647L
#if SCHAR_MAX >= TARGET_MAX
typedef signed char int32;
#elif SHORT_MAX >= TARGET_MAX
typedef short int32;
#elif INT_MAX >= TARGET_MAX
typedef int int32;
#else
typedef long int32;
#endif
#undef TARGET_MAX
If stdint.h is not available for your system, make your own. I always have a file called "types.h" that have typedefs for all the signed/unsigned 8, 16, and 32 bit values.
You can declare 32 bits with signed or unsigned long.
int32_t variable_name;
uint32_t variable_name;
also depending on your target platforms you can use autotools for your build system
it will see if stdint.h/inttypes.h exist and if they don't will create appropriate typedefs in a "config.h"
stdint.h is the obvious choice, but it's not necessarily available.
If you're using a portable library, it's possible that it already provides portable fixed-width integers.
For example, SDL has Sint32 (S is for “signed”), and GLib has gint32.

Resources