Variable affected by type conversion - c

I have always thought that when a variable is typecast, a copy of it results and any changes affect that temporary variable. But, the screenshot below indicates otherwise. Apparently, the original variable is what changes. Why? I am curious because I have never seen anything similar.

sprintf nul-terminates the string it outputs into the provided buffer. As the %010lu format specifier requests a number padded to be at least 10 digits long, you are consistently overflowing crc_buf and triggering UB. In your specific case, the least significant byte of crc gets trampled.
Make crc_buf 11 characters or more, and use snprintf instead of sprintf to catch this class of errors. For maximal portability, you could also use the PRIu32 format macro instead of casting:
snprintf(crc_buf, sizeof crc_buf, "%10" PRIu32, crc);

Related

Different output with printf

I am trying to print the value of a particularly large value after reading it from the console. When I am trying to print it from two different ways, one directly after assigning, one with the return value from the strtol function, I get different output! Can someone please explain me why I am noticing two different outputs?
Input value is: 4294967290
Here is the code snippet.
long int test2 = strtol(argv[1], &string, 10);
printf("the strtol value is %ld\n", test2);
printf("the strtol function value is %ld\n", strtol(argv[1], &string, 10));
Output
the strtol value is -6
the strtol function value is 4294967290
You need to do two things:
Add the line #include <stdlib.h> at the beginning of your program. That will cause strtol to be declared. (You also need #include <stdio.h> in order to declare printf.)
Add -Wall to your compiler flags (if you are using gcc or clang). That will cause the compiler to tell you that you need to declare strtol, and it might even suggest which header to include.
What is going on is that you haven't declared strtol, with the result that the compiler assumes that it returns an int.
Since 4294967290 is 232-6, it is the 32-bit Two's-complement representation of -6. Because the compiler assumes that strtol returns an int, the code it produces only looks at the low-order 32 bits. Since you are assigning the value to a long, the compiler needs to emit code which sign-extends the int. In other words, it takes the low-order 32 bits as though they were a signed integer (which would be -6) and then widens that -6 to a long.
In the second call to printf, the return value of strtol is inserted in the printf argument list without conversion. You tell printf that the argument is a long (by using the l flag in %ld), and by luck the entire 64 bits are in the argument list, so printf reads them out as a long and prints the "correct" value.
Needless to say, all this is undefined behaviour, and the actual output you are seeing is in no way guaranteed; it just happens to work that way with your compiler on your architecture. On some other compiler or on some other architecture, things might have been completely different, including the bit-length of int and long. So the above explanation, although possibly interesting, is of no practical value. Had you simply included the correct header and thereby told the compiler the real return type of strtol, you would have gotten the output you expected.

How to Right Pad a Hexadecimal in C

So I know (after a lot of confusing google searching) that to right pad a string, one would use fprintf("%-10s", string), or something like that to pad with spaces up to 10 length.
So I have two questions:
I know that left-pad is similar, but what would the syntax for it be? (I'm sorry, I did google, but got confused by conflicting answers...)
And more importantly, how would I right-pad a hexidecimal? Say I have an int i want to convert to hex with %02X. Could I still use %-1002X ? Wouldn't that screw it up?
printf conversion formats allow you to either left-pad or right-pad the conversion result, but not both at the same time. Right-padding an integer conversion is the same as right padding anything else - just specify the negative field width, like %-10x. You cannot both left-pad and right-pad at the same time: you can only specify only one width in the format. Your original %02x is already explicitly using left padding. You cannot add right-padding on top of that.
However, it looks like the purpose of your %02x is to produce zero-padded output that has at least 2 digits. This can be achieved through using precision component of the format instead of using width. Format like %.2x will also successfully produce 2 digit hex conversion.
By using precision instead of width, you leave width available for padding purposes. E.g. format like %-10.2x will produce 2-digit conversions (padded with zeros) that are right padded with spaces to 10 characters.
try
printf("Hex %8.8x", someInt);
Or use fprintf(), sprintf(), snprintf(), whatever... If you're starting with a hex string, use snprintf() with the %-8s format specifier to capture the translation into a char * buffer, and then use a for loop or to substitute spaces with '0' characters.

Printing hex integer by casting to char* and using "%s" in sprintf

I'm reading in two 32 bit registers and trying to put it inside a string buffer using the following:
sprintf (buffer, "%s-%s", ((char*)(in32(REGISTER1))) , (char*)(in32(REGISTER2)));
Can the hex value read in from the registers not be typecast as a pointer to a char and be printed into the buffer as above?
As craig65535 implies in a comment above, the problem is most likely with this phrase:
the hex value read in from the registers
I doubt that you're reading in a hex value; rather, you're reading in an integer. If you want to store a hex representation of that integer in a string, you'd use the %X format specifier:
sprintf (buffer, "%08X-%08X", in32(REGISTER1), in32(REGISTER2));
(The 8 means "use a width of eight characters"; the 0 means "left-pad with zeroes if the value is such that the width is less than eight".)
The only way you could validly cast to char * is if the integer value in the register is actually a pointer to some memory location where you've stored a string; but that is clearly not the case here.
sprintf(buffer, "%08x-%08x", REGISTER1, REGISTER2);
-- that's assuming you want the register addresses in your buffer. If your intention is to read the contents of the registers, adjust accordingly. The point though is you cannot simply call a number a char* and get the number out of it, but sprintf() (and all printf-like functions) can convert value bases for you.
As the others answers suggest, you can convert your integer to a string hex representation with sprintf using %X.
But as you didn't said what compiler you use or what the length of integer or long is, you could get unexpected results.
On a 16bit controller sprintf (buffer, "%08X-%08X", in32(REGISTER1),in32(REGISTER2)); would fail.
This should work on the most plattforms, as sprintf assume long values as arguments, and the arguments are always casted to longs.
sprintf (buffer, "%08lX-%08lX", (long)in32(REGISTER1), (long)in32(REGISTER2));

c passing unsigned long long value

How can the last two lines of one function be
printf("disk_free_blocks returning %llu\n",item_int3);
return (item_int3);
and out put
disk_free_blocks returning 233012428800
returning to calling function as
part_avail=disk_free_blocks(DiskParts[part_index].part_name,DISK_AVAIL);
if (DEBUG) printf("DiskParts[%d].part_name=%s has %llu free.\n",part_index,DiskParts[part_index].part_name,part_avail);
and output be
DiskParts[0].part_name=/dev/sda1 has 1084194816 free.
??
unsigned long long part_avail, item_int3;
The two output numbers are:
0x00000036409F8000
and
0x409F8000
It appears that the return type (which you haven't shown) isn't large enough to accomodate a 64-bit value, so the compiler simply truncates (which is the behavior required by the standard, for narrowing conversions on unsigned integers).
I tend to think these are both wrong: 233 billion blocks, with a 512 byte block, that is 100 TB. Not likely. 1 billion blocks is then around 512 GB, which might or might not match your actual /dev/sda1 free space.
unsigned long long part_avail, item_int3;
This doesn't make sense, since the usage of these two variables is in different scopes. Are there two variables with the same name? Or are you using global variables?
Possibly item_int3 inside the function is only 32 bits, printf reads past the end of the argument list during vararg processing, and the stack just happened to have 0x00000036 on it, so that got printed by the %llu specifier. When returned as an unsigned long long, the compiler properly zero-extends the value, and then the caller pushes the full 64-bit value onto the stack, which is retrieved and printed correctly during printf vararg processing of the %llu format code.
The return value was truncated to 32 bits somewhere along the way. Perhaps disk_free_blocks is declared as returning an int?
RESOLVED
disk_free_blocks() resided in a different file than process_copy_out(), the function making the call to disk_free_blocks.
The fix was adding a function prototype to inform the compiler.
Thank you everyone for your help.

Integer Overflow

I have an unsigned long long that I use to track volume. The volume is incremented by another unsigned long long. Every 5 seconds I print this value out and when the value reaches the 32 bit unsigned maximum the printf gives me a negative value. The code snippet follows:
unsigned long long vol, vold;
char voltemp[10];
vold = 0;
Later...
while (TRUE) {
vol = atoi(voltemp);
vold += vol;
fprintf(fd2, "volume = %llu);
}
What am I doing wrong? This runs under RedHat 4 2.6.9-78.0.5.ELsmp gcc version 3.4.5
Since you say it prints a negative value, there must be something else wrong, apart from your use of atoi instead of strtoull. A %llu format specifier just doesn't print a negative value.
It strongly looks like the problem is the fprintf call. Check that you included stdio.h and that the argument list is indeed what is in the source code.
Well I can't really tell because your code has syntax errors, but here is a guess:
vol = atoi(voltemp);
atoi converts ascii to integer. You might want to try atol but that only gets it to a long, not a long long.
Your C standard library MIGHT have atoll.
You can't use atoi if the number can exceed the bounds of signed int.
EDIT: atoll (which is apparently standard), as suggested, is another good option. Just keep in mind that limits you to signed long long. Actually, the simplest option is strtoull, which is also standard.
Are you sure fprintf can take in a longlong as a parameter, rather than a pointer to it? It looks like it is converting your longlong to an int before passing it in.
I'd guess the problem is that printf is not handling %llu the way you think it is.
It's probably taking only 32 bits off the stack, not 64.
%llu is only standard since C99. maybe your compiler likes %LU better?
For clarification the fprintf statement was copied incorrectly (my mistake, sorry). The fprintf statement should actually read:
fprintf(fd2, "volume = %llu\n", vold);
Also, while admittedly sloppy the maximum length of the the array voltemp is 9 bytes (digits) which is well within the limits of a 32-bit integer.
When I pull this code out of the program it is part of and run it in a test program I get the result I would expect which is puzzling.
If voltemp is ever really big, you'll need to use strtoull, not atoi.

Resources