Machine-independent printf() of int64_t? [duplicate] - c

This question already has answers here:
How to portably print a int64_t type in C
(7 answers)
Closed 4 months ago.
Consider the following snippet, compiled with gcc -Wall for two different architectures:
int64_t x;
printf("A: %ld\n", x);
printf("B: %lld\n", x);
When compiling for a 32 bit machine, the compiler complains about "A":
format '%ld' expects argument of type 'long int', but argument 2 has type 'int64_t' {aka 'long long int'}
When compiling for a 64 bit machine, the compiler complains about "B":
format '%lld' expects argument of type 'long long int', but argument 2 has type 'int64_t' {aka 'long int'}
The question: What is a sensible machine-independent way to printf() int64_t?

The header inttypes.h contains portable conversion specifiers for printf and scanf family of functions. (It also internally includes stdint.h.)
#include <inttypes.h>
int64_t x = ...;
printf("%"PRIi64, x);
See the C standard C17 7.8.1 for details.

Related

Long double output as 0.000000000000 in c lang

I am coding in Code::Blocks, in the C programming language:
#include <stdio.h>
int main() {
float var1 = 3.145926535897932;
double var2 = 3.145926535897932;
long double var3 = 3.14159265389793213456;
printf("%d\n", sizeof(float));
printf("%d\n", sizeof(double));
printf("%d\n", sizeof(long double));
printf("%.16f\n", var1);
printf("%.16f\n", var2);
printf("%.21Lf\n", var3);
return 0;
}
I am getting output as:-
4
8
16
3.1459264755249023
3.1459265358979320
0.000000000000000000000
Why am I getting 0.000000000000000000000 instead of 3.14159265389793213456, does my system does not support long double or is there a mistake in my code?
And if long double does not work in my system how it is able to give output of size of long double?
On my system (OS/X with clang), I get the expected output:
4
8
16
3.1459264755249023
3.1459265358979320
3.141592653897931963769
Yet the compiler produces many warnings:
clang -O3 -funsigned-char -std=c11 -Weverything -Wno-padded -Wno-shorten-64-to-32 -Wno-missing-prototypes -Wno-vla -Wno-missing-nor
eturn -Wno-sign-conversion -Wno-unused-parameter -Wwrite-strings -lm -lcurses -o 220306-longdouble 220306-longdouble.c
220306-longdouble.c:4:18: warning: implicit conversion loses floating-point precision: 'double' to 'float' [-Wconversion]
float var1 = 3.145926535897932;
~~~~ ^~~~~~~~~~~~~~~~~
220306-longdouble.c:6:24: warning: implicit conversion increases floating-point precision: 'double' to 'long double'
[-Wdouble-promotion]
long double var3 = 3.14159265389793213456;
~~~~ ^~~~~~~~~~~~~~~~~~~~~~
220306-longdouble.c:7:20: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("%d\n", sizeof(float));
~~ ^~~~~~~~~~~~~
%lu
220306-longdouble.c:8:20: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("%d\n", sizeof(double));
~~ ^~~~~~~~~~~~~~
%lu
220306-longdouble.c:9:20: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("%d\n", sizeof(long double));
~~ ^~~~~~~~~~~~~~~~~~~
%lu
220306-longdouble.c:10:23: warning: implicit conversion increases floating-point precision: 'float' to 'double'
[-Wdouble-promotion]
printf("%.16f\n", var1);
~~~~~~ ^~~~
6 warnings generated.
Here are the explanations:
the value produced by the sizeof operator has type size_t which is different from int: you should either case it as (int) or use the printf conversion specifier %zu.
the float value should be initialized from a float constant: float var1 = 3.145926535897932F;
the long double value should be initialized from a long double constant: long double var1 = 3.145926535897932L;
In the call printf("%.16f\n", var1), var1 is implicitly converted to type double as specified for variable arguments in vararg functions. You might make this conversion explicit to silence this warning, showing the behavior is expected.
the call printf("%.21Lf\n", var3); conforms to the C99 Standard, but the C library on your system seems incompatible with the compiler in use regarding the type long double.
Microsoft decided more than 10 years ago to map type long double to type double in their tools (cf Why did Microsoft abandon long double data type? ).
The compiler you use on your system seems to handle long double in a different way that is incompatible with the C library your program links to. It is also possible that this library does not conform to the C99 specification, eg: the %Ld conversion for type long double, or uses a different ABI to pass long double values. Older Microsoft C libraries are known to have such problems decades after the C Standard was published. You should try and upgrade the system or switch to a conformant C development system.
Here is a modified version, that no longer has undefined behavior, but probably still won't produce the expected output on your system:
#include <stdio.h>
int main() {
float var1 = 3.145926535897932F;
double var2 = 3.145926535897932;
long double var3 = 3.14159265389793213456L;
printf("%d\n", (int)sizeof(float));
printf("%d\n", (int)sizeof(double));
printf("%d\n", (int)sizeof(long double));
printf("%.16f\n", (double)var1);
printf("%.16f\n", var2);
printf("%.21Lf\n", var3);
return 0;
}
Output:
4
8
16
3.1459264755249023
3.1459265358979320
3.141592653897931963769

what does mean this exception ? format %d expects argument of type 'int', but argument 2 has type 'long long unsigned int' [-Wformat] [duplicate]

This question already has answers here:
How should I print types like off_t and size_t?
(10 answers)
Closed 2 years ago.
I'm a student trying to learn C and C++, I've got a problem with the specifier %d I dont't understand the exception that is written in the console, It's writing
The format %d expects argument of type 'int', but argument 2 has type 'long long unsigned int' [-Wformat]
Here is the code :
#include<stdio.h>
#include<stdlib.h>
int main()
{
short int u=1;
int v=2;
long int w=3;
char x='x';
float y=4;
double z=5;
long double a=6;
long b=7;
printf("short int:%d\n",sizeof(u));
printf("int:%d octets\n",sizeof(v));
printf("long int:%d octets\n",sizeof(w));
printf("char:%d octets\n",sizeof(x));
printf("float:%d octets\n",sizeof(y));
printf("double:%d octets\n",sizeof(z));
printf("long double:%d octets\n",sizeof(a));
printf("long:%d octets\n",sizeof(b));
return 0;
}
The type of the value returned by the operator sizeof is the unsigned integer type size_t The conversion specifier d is used to output values of the type int. You have to use the conversion specifier zu. Otherwise you will get undefined behavior.
For example
printf("short int:%zu\n",sizeof(u));
From the C Standard (7.21.6.1 The fprintf function)
9 If a conversion specification is invalid, the behavior is
undefined.275) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
The sizeof operator returns a size_t type. This is always unsigned and, on your platform, is a long long unsigned int; on other platforms, it may be just unsigned long or, indeed, some other (unsigned) integer type.
Use the %zu format specifier for arguments of this type; this will work whatever the actual size_t type definition happens to be.

How to printf a size_t without warning in mingw-w64 gcc 7.1?

I am using the mingw-w64 (x64) fork of minGW as prepared on nuwen.net. This is from the 7.1 version of gcc :
gcc --version
gcc (GCC) 7.1.0
I am compiling this program:
#include <stdio.h>
int main(void)
{
size_t a = 100;
printf("a=%lu\n",a);
printf("a=%llu\n",a);
printf("a=%zu\n",a);
printf("a=%I64u\n",a);
}
with warnings and c11 standard:
gcc -Wall -Wextra -Wpedantic -std=c11 test_size_t.c
and I get these warnings:
test_size_t.c: In function 'main':
test_size_t.c:6:14: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t {aka long long unsigned int}' [-Wformat=]
printf("a=%lu\n",a);
~~^
%I64u
test_size_t.c:6:14: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t {aka long long unsigned int}' [-Wformat=]
printf("a=%lu\n",a);
~~^
%I64u
test_size_t.c:7:14: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("a=%llu\n",a);
^
test_size_t.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%llu\n",a);
^~~~~~~~~~
test_size_t.c:7:14: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("a=%llu\n",a);
^
test_size_t.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%llu\n",a);
^~~~~~~~~~
test_size_t.c:8:13: warning: unknown conversion type character 'z' in format [-Wformat=]
printf("a=%zu\n",a);
^
test_size_t.c:8:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%zu\n",a);
^~~~~~~~~
test_size_t.c:8:13: warning: unknown conversion type character 'z' in format [-Wformat=]
printf("a=%zu\n",a);
^
test_size_t.c:8:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%zu\n",a);
^~~~~~~~~
test_size_t.c:9:9: warning: ISO C does not support the 'I64' ms_printf length modifier [-Wformat=]
printf("a=%I64u\n",a);
^~~~~~~~~~~
test_size_t.c:9:9: warning: ISO C does not support the 'I64' ms_printf length modifier [-Wformat=]
I would like to printf a size_t without warning but don't know the correct format specifier in this situation.
The problem is not the compiler but the C library. MinGW uses Microsoft's "Visual C Runtime" (msvcrt) which only conforms to c89 and it doesn't support the z format specifier.
Here's what you can do to safely print a size_t when using MinGW:
#include <inttypes.h>
#include <stdio.h>
#ifdef _WIN32
# ifdef _WIN64
# define PRI_SIZET PRIu64
# else
# define PRI_SIZET PRIu32
# endif
#else
# define PRI_SIZET "zu"
#endif
int main(void)
{
size_t mySize = 24;
printf("%" PRI_SIZET "\n", mySize);
}
On win64, you would get a warning with this code, because PRIu64 expands to the msvcrt-specific I64u format specifier. But you can silence this warning with the GCC flag -Wno-pedantic-ms-format.
Note that you need a similar trick for long long (here using PRIu64 on both 32bit and 64bit windows) because msvcrt doesn't know ll either.
edit: as pointed out by #M.M in a comment, you can instead link MinGW-provided alternative stdio functions that support C11 with #define __USE_MINGW_ANSI_STDIO 1. I prefer not to link extra code if I can get around the peculiarities of msvcrt, but that's of course a matter of taste.
The alternative solution as mentioned in comments is to toss in the __USE_MINGW_ANSI_STDIO compiler switch:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
int main(void)
{
size_t a = 100;
printf("a=%lu\n",a);
printf("a=%llu\n",a);
printf("a=%zu\n",a);
printf("a=%I64u\n",a);
}
This makes the code compile as expected and gcc now gives the appropriate warnings:
warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t' [-Wformat=]
warning: ISO C does not support the 'I' printf flag [-Wformat=]
warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'size_t' [-Wformat=]
Alternatively you can define the macro on command line with -D__USE_MINGW_ANSI_STDIO=1
PRIuPTR trick works (Cross platform format string for variables of type size_t?):
#include <stdio.h>
#include <inttypes.h>
int main()
{
size_t a = (size_t)(1024ULL * 1024 * 1024 * 1024 + 13);
printf("a = %" PRIuPTR "\n", a);
printf("sizeof(size_t) = %" PRIuPTR "\n", sizeof(size_t));
printf("sizeof(uintptr_t) = %" PRIuPTR "\n", sizeof(uintptr_t));
return 0;
}
Output x86:
a = 13
sizeof(size_t) = 4
sizeof(uintptr_t) = 4
Output x64:
a = 1099511627789
sizeof(size_t) = 8
sizeof(uintptr_t) = 8

How sizeof operator works in C? [duplicate]

This question already has an answer here:
Output data type of sizeof() operator
(1 answer)
Closed 4 years ago.
In this below code:
#include<stdio.h>
int main(void)
{
printf("%d",sizeof(int));
return 0;
}
When compiled on gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 compiler it gives warning:
format ‘%d’ expects argument of type ‘int’, but argument 2 has type
‘long unsigned int’ [-Wformat=] printf("%d",sizeof(int));
Why I am getting this warning? Is it that return type of sizeof is 'long unsigned int' ?
When I replaced '%d' with '%ld' the warning went.
The sizeof operator is processed at compile time (and can be applied on both types and expressions). It gives some constant* of type size_t. On your system (and mine Debian/Linux/x86-64 also) sizeof(int) is (size_t)4. That size_t type is often typedef-ed in some type like unsigned long (but what integral type it actually is depends upon the implementation). You could code
printf("%d", (int)sizeof(int));
or (since printf understands the %zd or %zu control format string for size_t)
printf("%zu", sizeof(int));
For maximum portability, use %zu (not %ld) for printing size_t (because you might find systems or configurations on which size_t is unsigned int etc...).
Note *: sizeof is always constant, except for VLA

Getting Warning When Using SizeOf [duplicate]

This question already has answers here:
'%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Wformat=] [duplicate]
(3 answers)
Closed 9 years ago.
I am getting a warning warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat]
I am writing a very basic program which gives the size of the data type but in the Linux environment I am getting this warning whereas in Visual Studio, the program works without any warning. The source code is as below :-
#include<stdio.h>
int main()
{
int a;
printf("\nThe Size Of Integer A Is = \t%d", sizeof(a));
return 0;
}
Answer will be appreciated and also can anyone tell me a proper way of solving such kind of warnings as I am new to this C and it's standard.
sizeof returns size_t type. Use %zu specifier to print the value of sizeof.
printf("\nThe Size Of Integer A Is = \t%zu", sizeof(a));
C11 6.5.3.4 The sizeof and _Alignof operators:
5 The value of the result of both operators is implementation-defined, and its type (an
unsigned integer type) is size_t, defined in <stddef.h> (and other headers).
NOTE: As loreb pointed out in his comment that when you will compile your code in Windows, then most probably you will get the warning like:
[Warning] unknown conversion type character 'z' in format [-Wformat]
[Warning] too many arguments for format [-Wformat-extra-args]
sizeof return size_t and not int
Use %zu in printf
In C99 the correct format for a size_t variable is %zu.
Use:
printf("\nThe Size Of Integer A Is = \t%zu", sizeof(a));

Resources