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
Related
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.
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
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
I just wrote something to test the sizeof operator.
Firstly, when I build this program, GCC give me a warning.
main(){
printf("%d", (2*3.14f));
}
// test.c|2|warning: format '%d' expects argument of type 'int',
// but argument 2 has type 'double' [-Wformat=]
So GCC believes the type of (2*3.14f) is double.
Then I added a sizeof operator, I assume the output will be exactly 8, which is the size of double.
main(){
printf("%d", sizeof(2*3.14f));
}
//Output: 4
This is really confusing. So the question is: what is the type of (2*3.14f)?
(2*3.14f) has type float. It is promoted to double when passed to a variadic function, hence the reference to double in the error message from GCC.
If you wish to display a float converted to int, use printf("%d", (int)…);
If you wish to display the bits of a float as if it were an int, use:
int i;
assert(sizeof(f) == sizeof(i));
memcpy(&i, &f, sizeof(f));
printf("%d", i);
Both invocations have undefined behaviour. Indeed, the first argument has type double and the second size_t, so you must use format specifiers %f and %zu, respectively.
(The type of 2 * 3.14f is float, because of the usual arithmetic conversions, but the argument is promoted to double under the floating point conversions because you're passing it as a variable argument.)
When I try to compile this code:
void main()
{
float x;
x=6.5;
printf("Value of x is %f, address of x %ld\n", x, &x);
}
it gives me this error:
pruebaso.c: In function ‘main’:
pruebaso.c:5:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("Value of x is %f, address of x %ld\n", x, &x);
^
pruebaso.c:5:9: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘float *’ [-Wformat=]
I've seen in another forum the solution is to make a cast to a void pointer first:
http://www.linuxquestions.org/questions/programming-9/beginning-c-programming-how-to-print-memory-locations-printf-conversion-number-927305/
But making this change,
printf("Value of x is %f, address of x %ld\n", (double)x, (void *)&x);
now gives me a warning:
pruebaso.c: In function ‘main’:
pruebaso.c:5:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("Value of x is %f, address of x %ld\n", (double)x, (void *)&x);
^
pruebaso.c:5:9: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘void *’ [-Wformat=]
Could someone explain me how could I solve it without getting a warning?
Thank you
You need to include <stdio.h> to suppress the first warning and use a cast to void * and use %p to suppress the second warning.
In C90, using printf() without <stdio.h> invokes undefined behavior because the implicit declaration will not match the actual declaration, since printf() is variadic. (Using fputs() would be okay, by comparison.) In C99, implicit declarations are not allowed but GCC allows you to compile such code anyway.
#include <stdio.h>
int main(void)
{
float x = 6.5;
printf("Value of x is %f, address of x %p\n", x, (void *) &x);
}
The %p format specifier is used for printing pointers. Technically, it must be used with a char * or void * pointer. On modern systems, this will not affect the result; but passing other pointer types to %p will technically invoke undefined behavior (which is bad).
The %ld format in your code is wrong, even though it will work on most systems. First, it takes a long argument, which requires a cast (even though the cast will only make a difference on a few systems). Second, even if you add the cast, not all information in the pointer is guaranteed to remain (it might chop off bits or do something else). In practice, 64-bit Windows systems are the only systems where a cast to long chops of bits and the cast works fine everywhere else.
So use %p and cast to void *.
void main()
{
float x;
x=6.5;
printf("Value of x is %f, address of x %ld\n", x, &x);
}
The immediate problem is that you're missing the required #include <stdio.h>, but that's not the only problem with your code. Some of these things are errors that you can probably get away with (compilers may not complain, and may generate code that does what you expect), but there's no reason not to do it right.
#include <stdio.h>
int main(void)
{
float x;
x = 6.5;
printf("Value of x is %f, address of x %p\n", x, (void*)&x);
}
To explain the changes I made:
#include <stdio.h> is required for any program that calls printf. More precisely, a declaration of printf is required, and <stdio.h> provides it. (In principle you could write your own declaration instead, but there's no good reason to do so.)
The correct definition of main is int main(void). void main() may be accepted by some compilers, but it's useful mostly as a way to detect bad books. If you're using a book that tells you to use void main(), its author does not know the language very well, and may have given you other misinformation. Find a better book. (Caveat: void main(), or more likely void main(void) might actually be the preferred implementation-defined form for some embedded systems. but you're probably not using such a system.)
The "%ld" format requires an argument of type long int. The only correct format for printing a pointer value is "%p". Since "%p" requires an argument of type void*, you should explicitly cast your pointer value to void*. Omitting the cast is likely to "work", but float* and void* are distinct types, and are not guaranteed to have the same representation or to be passed to functions in the same way.
C implicitly declares functions if you use them before defining it, which caused the error " incompatible implicit declaration of built-in function ‘printf’".
To fix this, add #include <stdio.h> at the top of the file (this copies over the header file that includes a declaration for printf.
The second thing issue is that you should use %p to print pointers.
The resulting code is
#include <stdio.h>
int main(void)
{
float x;
x=6.5;
printf("Value of x is %f, address of x %p\n", x, (void *) &x);
return 0;
}