I have this sample code for converting 32 bit integers to ip addresses.
#include <stdio.h>
int main()
{
unsigned int c ;
unsigned char* cptr = (unsigned char*)&c ;
while(1)
{
scanf("%d",&c) ;
printf("Integer value: %u\n",c);
printf("%u.%u.%u.%u \n",*cptr, *(cptr+1), *(cptr+2), *(cptr+3) );
}
}
This code gives incorrect output for input 2249459722 .
But when i replace
scanf("%d",&c) ;
by
scanf("%u",&c) ;
The output comes out to be correct.
P.S : I know about inet_ntop and inet_pton.
I expect answers other than suggesting those.
You are coding ‘sinfully‘ (making a number of mistakes which will hurt you sooner or later – mostly sooner). First off, you are assuming that the integer is of the correct endian-ness. On some machines, you will be wrong – either on Intel machines or on PowerPC or SPARC machines.
In general, you should show the actual results you get rather than just saying that you get the wrong result; you should also show the expected result. That helps people debug your expectations.
Here’s my modified version of your code – instead of requesting input, it simply assumes the value you specified.
When compiled on my Mac (Intel, little-endian), the output is:
When compiled on my Sun (SPARC, big-endian), the output is:
(Using GCC 4.4.2 on the SPARC, I get a warning:
Using GCC 4.2.1 on Mac – with lots of warnings enabled (
gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Werror) – I don’t get that warning, which is interesting.) I can remove that by adding aUsuffix to the integer constant.Another way of looking at the problems is illustrated with the following code and the extremely fussy compiler settings shown above:
This fails to compile (because of the
-Werrorsetting) with the message:Remove the
-Werrorsetting and it compiles, but then shows the next problem that you have – the one of not checking for error indications from functions that can fail:Basically, the
sscanf()function reports that it failed to convert the string to a signed integer (because the value is too large to fit – see the warning from GCC 4.4.2), but your code was not checking for the error return fromsscanf(), so you were using whatever value happened to be left incat the time.So, there are multiple problems with your code:
Alok’s Comment
Yes, the test on
sscanf()is wrong. That’s why you have code reviews, and also why it helps to post the code you are testing.I’m now a bit puzzled – getting consistent behaviour that I can’t immediately explain. With the obvious revision (testing on MacOS X 10.6.2, GCC 4.2.1, 32-bit and 64-bit compilations), I get one not very sane answer. When I rewrite more modularly, I get a sane answer.
I do not have a good explanation for the value 170.142.21.134; but it is consistent on my machine, at the moment.
Same value – even in 64-bit instead of 32-bit. Maybe the problem is that I’m trying to explain undefined behaviour, which is more or less by definition unexplainable (inexplicable).
Using the function argument like this means GCC cannot spot the bogus format any more.
The results are consistent here.
And these are the same as the 32-bit case. I’m officially bemused. The main observations remain accurate – be careful, heed compiler warnings (and elicit compiler warnings), and don’t assume that “all the world runs on Intel chips” (it used to be “don’t assume that all the world is a VAX”, once upon a long time ago!).