printf() error with long double and null pointer.

F

fieldfallow

Hello all,

Before stating my question, I should mention that I'm fairly new to C.

Now, I attempted a small demo that prints out the values of C's numeric
types, both uninitialised and after assigning them their maximum defined
values. However, the output of printf() for the long double 'ld' and the
pointer of type void 'v_p', after initialisation don't seem to be right.

The compiler used was gcc (mingw) with '-Wall', '-std=c99' and
'-pedantic' switches. No warnings were emitted. Incidentally the MS
Visual C++ 2003 compiler's output seems okay. I give them both below:

gcc's output:
ld == -1.#QNAN0
or -1.#QNAN
v_p == FFFFFFFF

msvc's output:
ld == 179769313486231570000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000.000000
or 1.79769e+308
v_p == 00000000

I thought null pointers had a value of zero. Why is gcc's executable
printing ffffffffh? Also the value of 'ld' seems to be wrong.

The code for the demo is:
#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void) {
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
long double ld;
void *v_p;

printf("c == %c\n\tor %d\nuc == %c\n\tor %u\ns == %hd\nus == %hu\n"
"i == %d\nui == %u\nl == %ld\nul == %lu\nf == %f\n\tor %g\n"
"d == %lf\n\tor %g\nld == %Lf\n\tor %Lg\nv_p == %p\n",
c,c,uc,uc,s,us,i,ui,l,ul,f,f,d,d,ld,ld,v_p);

puts("Initialising them with their maximum allowed values...");
c = CHAR_MAX;
uc = UCHAR_MAX;
s = SHRT_MAX;
us = USHRT_MAX;
i = INT_MAX;
ui = UINT_MAX;
l = LONG_MAX;
ul = ULONG_MAX;
f = FLT_MAX;
d = DBL_MAX;
ld = LDBL_MAX;
puts("Initialising v_p with NULL...");
v_p = NULL;

printf("c == %c\n\tor %d\nuc == %c\n\tor %u\ns == %hd\nus == %hu\n"
"i == %d\nui == %u\nl == %ld\nul == %lu\nf == %f\n\tor %g\n"
"d == %lf\n\tor %g\nld == %Lf\n\tor %Lg\nv_p == %p\n",
c,c,uc,uc,s,us,i,ui,l,ul,f,f,d,d,ld,ld,v_p);
return 0;
}

Where is the mistake?
Thanks for all the help.
 
P

pete

fieldfallow said:
Hello all,

Before stating my question,
I should mention that I'm fairly new to C.

Now, I attempted a small demo that prints out
the values of C's numeric types, both uninitialised

Accessing uninitialised values like that,
causes undefined behavior in your program.
The undefined behavior can show up in any part
of the program's execution.
 
F

fieldfallow

pete said:
Accessing uninitialised values like that,
causes undefined behavior in your program.
The undefined behavior can show up in any part
of the program's execution.

Does even printing out the values cause undefined behaviour? Is any
other operation legal, or must I assign them values before I do anything
with them?

Thanks for your answers. The C book I currently have is not very clear
on this point.
 
R

Robin Haigh

fieldfallow said:
Hello all,

Before stating my question, I should mention that I'm fairly new to C.

Now, I attempted a small demo that prints out the values of C's numeric
types, both uninitialised and after assigning them their maximum defined
values. However, the output of printf() for the long double 'ld' and the
pointer of type void 'v_p', after initialisation don't seem to be right.

The compiler used was gcc (mingw) with '-Wall', '-std=c99' and
'-pedantic' switches. No warnings were emitted. Incidentally the MS
Visual C++ 2003 compiler's output seems okay. I give them both below:

gcc's output:
ld == -1.#QNAN0
or -1.#QNAN
v_p == FFFFFFFF

msvc's output:
ld == 179769313486231570000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000.000000
or 1.79769e+308
v_p == 00000000

I thought null pointers had a value of zero. Why is gcc's executable
printing ffffffffh? Also the value of 'ld' seems to be wrong.

The code for the demo is:
#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void) {
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
long double ld;
void *v_p;

printf("c == %c\n\tor %d\nuc == %c\n\tor %u\ns == %hd\nus == %hu\n"
"i == %d\nui == %u\nl == %ld\nul == %lu\nf == %f\n\tor %g\n"
"d == %lf\n\tor %g\nld == %Lf\n\tor %Lg\nv_p == %p\n",
c,c,uc,uc,s,us,i,ui,l,ul,f,f,d,d,ld,ld,v_p);

puts("Initialising them with their maximum allowed values...");
c = CHAR_MAX;
uc = UCHAR_MAX;
s = SHRT_MAX;
us = USHRT_MAX;
i = INT_MAX;
ui = UINT_MAX;
l = LONG_MAX;
ul = ULONG_MAX;
f = FLT_MAX;
d = DBL_MAX;
ld = LDBL_MAX;
puts("Initialising v_p with NULL...");
v_p = NULL;

printf("c == %c\n\tor %d\nuc == %c\n\tor %u\ns == %hd\nus == %hu\n"
"i == %d\nui == %u\nl == %ld\nul == %lu\nf == %f\n\tor %g\n"
"d == %lf\n\tor %g\nld == %Lf\n\tor %Lg\nv_p == %p\n",
c,c,uc,uc,s,us,i,ui,l,ul,f,f,d,d,ld,ld,v_p);
return 0;
}

Where is the mistake?
Thanks for all the help.

Works for me running gcc on Cygwin.

%lf (alternative to %f) for double is a new feature in C99. Does your
printf support it?

If you're not on Linux or Cygwin, you may be using your system's libc, in
which case you get what you get, notwithstanding the C99 flag.
 
P

pete

fieldfallow said:
Does even printing out the values cause undefined behaviour?
Yes.

Is any
other operation legal, or must I assign them values before I do
anything with them?

For uninitialised objects,
you can only portably do operations which don't access the values.
That's pretty much limited to having the variables be
operands of the address operator and or the sizeof operator.
 
R

Richard Tobin

Accessing uninitialised values like that,
causes undefined behavior in your program.
The undefined behavior can show up in any part
of the program's execution.
[/QUOTE]
Does even printing out the values cause undefined behaviour?

Yes, but I would be surprised if it caused the behaviour shown.
Try removing the first printf and see if you still get the same
results for the second.

-- Richard
 
F

fieldfallow

Does even printing out the values cause undefined behaviour?

Yes, but I would be surprised if it caused the behaviour shown.
Try removing the first printf and see if you still get the same
results for the second.[/QUOTE]

Yes. Even after commenting out the first printf(), I still get the same
wrong output. Would this indicate a fault in the particular toolchain,
i.e. gcc (MinGW)?

The output is:
Initialising them with their maximum allowed values...
Initialising v_p with NULL...
c == 
or 127
uc == ÿ
or 255
s == 32767
us == 65535
i == 2147483647
ui == 4294967295
l == 2147483647
ul == 4294967295
f == 340282346638528860000000000000000000000.000000
or 3.40282e+038
d == 17976931348623157000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000.000000
or 1.79769e+308
ld == -1.#QNAN0
or -1.#QNAN
v_p == FFFFFFFF

Thanks.
 
P

pete

fieldfallow said:
ld == -1.#QNAN0
or -1.#QNAN

That result is also wrong.

Are you using still using %lf to output doubles?

%f is for both doubles and floats.

C99 allows %lf for doubles, but most compilers are C90
where using %lf to output a double is also undefined.
 
R

Richard Tobin

fieldfallow said:
Yes. Even after commenting out the first printf(), I still get the same
wrong output. Would this indicate a fault in the particular toolchain,
i.e. gcc (MinGW)?

Perhaps a bug in the handling of long double. Take out the long
double values and see if the pointer has the expected value. Or put
in some plain integers after the long doubles and see if they are
wrong. (As far as I know, %p is not required to print any particular
value for null pointers, but it will almost certainly be zero.)

-- Richard
 
F

fieldfallow

Robin said:
Works for me running gcc on Cygwin.

Strange. My compiler is gcc 3.4.5 for MinGW 5.0
%lf (alternative to %f) for double is a new feature in C99. Does your
printf support it?

I think so. The output for the double seems to be correct. Only those of
the long double and void pointer seem to be wrong. I'm saying this
because the MS Visual C++ 2003 toolkit compiler's output for the double
tallies with gcc. In addition the max. for long double is the same as
double and void pointer prints out zero after assigning NULL to it.
If you're not on Linux or Cygwin, you may be using your system's libc, in
which case you get what you get, notwithstanding the C99 flag.

In this case, the MSVC compiled executable should also exhibit the same
error, shouldn't it.

Anyway, this seems to be heading a bit off-topic here. Maybe a MinGW
group would be better.

Thanks everyone for your help.
 
P

pete

pete said:
That result is also wrong.

Are you using still using %lf to output doubles?

%f is for both doubles and floats.

C99 allows %lf for doubles, but most compilers are C90
where using %lf to output a double is also undefined.

I'm suggesting that the error may have occured just
before the long double output.
 
F

fieldfallow

pete said:
That result is also wrong.

Are you using still using %lf to output doubles?

%f is for both doubles and floats.

C99 allows %lf for doubles, but most compilers are C90
where using %lf to output a double is also undefined.

Okay, I switched to %f for both floats and doubles and kept the first
printf() commented out, and still the same error.

Output:
Initialising them with their maximum allowed values...
Initialising v_p with NULL...
c == 
or 127
uc == ÿ
or 255
s == 32767
us == 65535
i == 2147483647
ui == 4294967295
l == 2147483647
ul == 4294967295
f == 340282346638528860000000000000000000000.000000
or 3.40282e+038
d == 179769313486231570000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000.000000
or 1.79769e+308
ld == -1.#QNAN0
or -1.#QNAN
v_p == FFFFFFFF

Code is:
#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void) {
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
float f;
double d;
long double ld;
void *v_p;
/*
printf("c == %c\n\tor %d\nuc == %c\n\tor %u\ns == %hd\nus == %hu\n"
"i == %d\nui == %u\nl == %ld\nul == %lu\nf == %f\n\tor %g\n"
"d == %lf\n\tor %g\nld == %Lf\n\tor %Lg\nv_p == %p\n",
c,c,uc,uc,s,us,i,ui,l,ul,f,f,d,d,ld,ld,v_p);
*/
puts("Initialising them with their maximum allowed values...");
c = CHAR_MAX;
uc = UCHAR_MAX;
s = SHRT_MAX;
us = USHRT_MAX;
i = INT_MAX;
ui = UINT_MAX;
l = LONG_MAX;
ul = ULONG_MAX;
f = FLT_MAX;
d = DBL_MAX;
ld = LDBL_MAX;
puts("Initialising v_p with NULL...");
v_p = NULL;

printf("c == %c\n\tor %d\nuc == %c\n\tor %u\ns == %hd\nus == %hu\n"
"i == %d\nui == %u\nl == %ld\nul == %lu\nf == %f\n\tor %g\n"
"d == %f\n\tor %g\nld == %Lf\n\tor %Lg\nv_p == %p\n",
c,c,uc,uc,s,us,i,ui,l,ul,f,f,d,d,ld,ld,v_p);
return 0;
}

Thanks.
 
F

fieldfallow

Richard said:
Perhaps a bug in the handling of long double. Take out the long
double values and see if the pointer has the expected value. Or put
in some plain integers after the long doubles and see if they are
wrong. (As far as I know, %p is not required to print any particular
value for null pointers, but it will almost certainly be zero.)

-- Richard

Your right Richard. After completely removing the long double from
printf(), the void pointer's value is printed out as 00000000.

Also, declaring and initialising the long double with LDBL_MAX, but not
attempting to pass it to printf() also gives the correct output for the
void pointer.

So I guess it appears to be a bug in the printf()'s handling of long
double arguments.

Maybe it's been corrected by any recent patches, though my MinGW
distribution was installed only two months before.

Thanks for your help.
 
R

Richard Bos

fieldfallow said:
Yes. Even after commenting out the first printf(), I still get the same
wrong output.

It does that for me, too[0]. When I remove the references to long
doubles in the printf(), it prints the expected[1] value for v_p, too.
It appears at first glance that gcc and the MinGW library are not in
accord over the size of a long double. How pernicious.

Try this: print (using sizeof) the size of your double and long double.
Dev-C++ on this computer says 8 and 12, respectively. But the headers
claim that long double is the same as double, and all values in
Would this indicate a fault in the particular toolchain, i.e. gcc (MinGW)?

Yes.

Anyone know the right channel to report this to MinGW?

Richard

[0] Even when inserting the l in the second %g...
[1] Although not required.
 
P

pete

fieldfallow said:
ld == -1.#QNAN0
or -1.#QNAN
v_p == FFFFFFFF

The pointer is allowed to print out any way that
the implementation defines it,
but the long double output is just wrong.

I can't find any problems in the rest of your code.
I'm beginning to suspect your implementation.

For debugging,
it's good to see the smallest code which exhibits the problem.
Try this:

#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void)
{
float f;
double d;
long double ld;
void *v_p;
puts("Initialising them with their maximum allowed values...");
puts("Initialising v_p with NULL...");

f = FLT_MAX;
d = DBL_MAX;
ld = LDBL_MAX;
v_p = NULL;

printf( "f == %g\n"
"d == %g\n"
"ld == %Lg\n"
"v_p == %p\n"
, f, d, ld, v_p);
return 0;
}
 
F

fieldfallow

pete said:
The pointer is allowed to print out any way that
the implementation defines it,
but the long double output is just wrong.

I can't find any problems in the rest of your code.
I'm beginning to suspect your implementation.

Yes. Especially, when printf() is passed a long double argument,
arguments after it seem to get trashed.
For debugging,
it's good to see the smallest code which exhibits the problem.
Try this:

#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void)
{
float f;
double d;
long double ld;
void *v_p;
puts("Initialising them with their maximum allowed values...");
puts("Initialising v_p with NULL...");

f = FLT_MAX;
d = DBL_MAX;
ld = LDBL_MAX;
v_p = NULL;

printf( "f == %g\n"
"d == %g\n"
"ld == %Lg\n"
"v_p == %p\n"
, f, d, ld, v_p);
return 0;
}

Compiled with gcc -Wall -std=c99 -pedantic
Output is:
Initialising them with their maximum allowed values...
Initialising v_p with NULL...
f == 3.40282e+038
d == 1.79769e+308
ld == -1.#QNAN
v_p == 00007FFE

At this point it seems to be an error in my implementation's printf()
regarding long doubles. I'll writes some more demos and then try
reinstalling MinGW.

Thanks for your help.
 
R

Richard Bos

Richard G. Riley said:
Which part?

http://c-faq.com/null/nullor0.html

Clearly says that "C programmers must understand that NULL and 0 are
interchangeable in pointer contexts".

In addition:

"It is only in pointer contexts that NULL and 0 are equivalent"

In code. Nowhere else. Not in memory; not in output. NULL is a null
pointer constant, _not_ a null pointer object. (And note that that
question does talk about what the programmer should use in his code, not
about anything else.)
Apart from his uninitiliased issues, his comments about null pointers
having a value of zero is fairly common isnt it?

Very common, but also wrong.

Richard
 
P

pete

fieldfallow wrote:
At this point it seems to be an error in my implementation's printf()
regarding long doubles.

It does.
I'll writes some more demos and then try
reinstalling MinGW.

Thanks for your help.

You're welcome.

One reason that we obsess about undefined behavior in code here,
is that sometimes the effects are not where you expect to see them,
somewhat similarly to the way that the long double problem
affected the void pointer output.

I realise that this was not
a case of code containing undefined behavior,
but rather a case of it being the implementation's fault.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top