Problems with the read syscall [duplicate] - c

pixel_data is a vector of char.
When I do printf(" 0x%1x ", pixel_data[0] ) I'm expecting to see 0xf5.
But I get 0xfffffff5 as though I was printing out a 4 byte integer instead of 1 byte.
Why is this? I have given printf a char to print out - it's only 1 byte, so why is printf printing 4?
NB. the printf implementation is wrapped up inside a third party API but just wondering if this is a feature of standard printf?

You're probably getting a benign form of undefined behaviour because the %x modifier expects an unsigned int parameter and a char will usually be promoted to an int when passed to a varargs function.
You should explicitly cast the char to an unsigned int to get predictable results:
printf(" 0x%1x ", (unsigned)pixel_data[0] );
Note that a field width of one is not very useful. It merely specifies the minimum number of digits to display and at least one digit will be needed in any case.
If char on your platform is signed then this conversion will convert negative char values to large unsigned int values (e.g. fffffff5). If you want to treat byte values as unsigned values and just zero extend when converting to unsigned int you should use unsigned char for pixel_data, or cast via unsigned char or use a masking operation after promotion.
e.g.
printf(" 0x%x ", (unsigned)(unsigned char)pixel_data[0] );
or
printf(" 0x%x ", (unsigned)pixel_data[0] & 0xffU );

Better use the standard-format-flags
printf(" %#1x ", pixel_data[0] );
then your compiler puts the hex-prefix for you.

Use %hhx
printf("%#04hhx ", foo);

Then length modifier is the minimum length.

Width-specifier in printf is actually min-width. You can do printf(" 0x%2x ", pixel_data[0] & 0xff) to print lowes byte (notice 2, to actually print two characters if pixel_data[0] is eg 0xffffff02).

Related

Why is sscanf behaving like this when converting hex strings to number?

I have written a piece of code that I am using to research the behavior of different libraries and functions. And doing so, I stumbled upon some strange behavior with sscanf.
I have a piece of code that reads an input into a buffer, then tries to put that value into a numeric variable.
When I call sscanf from main using the input buffer, and the format specifier %x yields a garbage value if the input string is shorter than the buffer. Let's say I enter 0xff, I get an arbitrarily large random number every time. But when I pass that buffer to a function, all calls to scanf result in 255 (0xff) like I expect, regardless of type and format specifier mismatch.
My question is, why does this happen in the function main but not in the function test?
This is the code:
#include <stdio.h>
int test(char *buf){
unsigned short num;
unsigned int num2;
unsigned long long num3;
sscanf(buf, "%x", &num);
sscanf(buf, "%x", &num2);
sscanf(buf, "%x", &num3);
printf("%x", num);
printf("%x", num2);
printf("%x", num3);
return 0;
}
void main(){
char buf[16];
unsigned long long num;
printf("%s","Please enter the magic number:");
fgets(buf, sizeof(buf),stdin);
sscanf(buf, "%x", &num);
printf("%x\n", num);
test(&buf);
}
I expect the behavior to be cohesive; all calls should fail, or all calls should succeed, but this is not the case.
I have tried to read the documentation and do experiments with different types, format specifiers, and so on. This behavior is present across all numeric types.
I have tried compiling on different platforms; gcc and Linux behave the same, as do Windows and msvc.
I also disassembled the binary to see if the call to sscanf differs between main() and test(), but that assembly is identical. It loads the pointer to the buffer into a register and pushes that register onto the stack, and calls sscanf.
Now just to be clear:
This happens consistently, and num in main is never equal to num, num2 or num3 in test, but num, num2 and num3 are always equal to each other.
I would expect this to cause undefined behavior and not be consistent.
Output when run - every time
./main
Please enter the magic number: 0xff
0xaf23af23423 <--- different every time
0xff <--- never different
0xff <--- never different
0xff <--- never different
The current reasoning I have is in one instance sscanf is interpreting more bytes than in the other. It seems to keep evaluating the entire buffer, getting impacted by residual data in memory.
I know I can make it behave correctly by either filling the buffer, with that last byte being a new line or using the correct format specifier to match the pointer type. "%llx" for main in this case. So that is not what I am wondering; I have made that error on purpose.
I am wondering why using the wrong format specifier works in one case but not in the other consistently when the code runs.
sscanf with %x should be used only with the address of an unsigned int. When an address of another object is passed, the behavior is not defined by the C standard.
With a pointer to a wider object, the additional bytes in the object may hold other values (possibly leftover from when the startup code prepared the process and called main). With a pointer to a narrower object, sscanf may write bytes outside of the object. With compiler optimization, a variety of additional behaviors are possible. These various possibilities may manifest as large numbers, corruption in data, program crashes, or other behaviors.
Additionally, printing with incorrect conversion specifiers is not defined by the C standard, and can cause errors in printf attempting to process the arguments passed to it.
Use %hx to scan into an unsigned short. Use %lx to scan into an unsigned long. Use %llx to scan into an unsigned long long. Also use those conversion specifiers when printing their corresponding types.
My question is, why does this happen in the function main but not in the function test?
One possibility is the startup code used a little stack space while setting up the process, and this left some non-zero data in the bytes that were later used for num in main. The bytes lower on the stack held zero values, and these bytes were later used for num3 in test.
The argument expression in this call
test(&buf);
has the type char ( * )[16] but the function expects an argument of the type char *
int test(char *buf){
There is no implicit conversion between these pointer types.
You need to call the function like
test( buf );
Also it seems there is a typo
printf("%s","Please enter the magic number:");
printf("%x\n", num);
The variable num is not initialized.
In this call
unsigned long long num;
//...
sscanf(buf, "%x", &num);
you are using the third argument of the type unsigned long long int * but the conversion specification "%x" expects an argument of the type unsigned int *. So the call has undefined behavior.
You need to write
sscanf(buf, "%llx", &num);
The same problem exists for the used variable num that has the type unsigned short
unsigned short num;
//...
sscanf(buf, "%x", &num);
You have to write
sscanf(buf, "%hx", &num);
The same length modifiers you need to use in calls of printf
printf("%hx", num);
printf("%x", num2);
printf("%llx", num3);
Here is a demonstration program.
#include <stdio.h>
int main( void )
{
char buf[] = "0xff\n";
unsigned short num;
unsigned int num2;
unsigned long long num3;
sscanf( buf, "%hx", &num );
sscanf( buf, "%x", &num2 );
sscanf( buf, "%llx", &num3 );
printf( "%hx\n", num );
printf( "%x\n", num2 );
printf( "%llx\n", num3 );
}
The program output is
ff
ff
ff

Displaying an integer to hex in C

I have this part of code in C class:
int i;
for (i=0;i<val;i++)
mdl_print ("%u ", rec->payload[i]);
mdl_print ("\n");
Variable rec->payload is uint8_t type. I would print it in hexadecimal notation.
How can I do? Thanks.
Quick and easy:
print("%x", (int)(rec->payload[i]));
To display in the format 0x05 then use:
print("0x%02x", ...)
instead.
If mdl_print() works like the standard C function printf(), try something like the following:
printf( "%02x", (int) rec->payload[i] );
The basic printf formatting code for writing in hexadecimal is %x. "02" means to pad the number with '0' until it's two characters wide, which is how you'd normally print an int8.
Many custom output functions follow the format of printf in this way, since it's very familiar to C programmers. You can read more about printf on its man page: http://linux.die.net/man/3/printf
Use "%x", so:
mdl_print ("%x ", rec->payload[i]);
This will give you a hex number that is the "length necessary". If you want a fixed length, use "%02x" for two digits padded with zeros.
Note that providing a uint8_t or int where an unsigned int is expected in printf is undefined behaviour, as stated by section 7.21.6.1p9 of n1570.pdf: "If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined." According to 7.21.6.1p8, %x tells printf to expect an unsigned int. Make sure you explicitly cast your uint8_t to (unsigned int), or use the PRIx8 macro found in <stdint.h>.
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint8_t foo = 42;
/* These two printfs are equivalent: */
printf("Hex for %02u: %02x\n", (unsigned int) foo, (unsigned int) foo);
printf("Hex for %02" PRIu8 ": %02" PRIx8 "\n", foo, foo);
return 0;
}
First your title is so wrong... Casting integer to hex in C casting implies a type change, hex is a number system not a type. You're "displaying an integer in hex" not "casting". If you don't understand the difference please ask for clarification.
As far as the displaying goes, it depends what you want the result to look like. One short cut that I typically use is:
mdl_print("%#x ", rec->payload[i]);
Which displays values as:
0xA6
The caveat on this syntax is that it doesn't work with 0, you don't get 0x0 just 0. So an alternative would be:
mdl_print("0x%x ", rec->payload[i]);
Which will display the value as 0xA6 or 0x0 or whatever it maybe. Of course if you don't want the 0x part you can always just do:
mdl_print("%x ", rec->payload[i]);
Your max value (in hex) with a unsigned 8-bit number is 0xFF so if you want them all to display the same "width" you can use the size specifier too:
mdl_print("%02x ", rec->payload[i]); // or mdl_print("0x%02x, rec->payload[i]);
// or whatever you picked

Printing int type with %lu - C+XINU

I have a given code, in my opinion there is something wrong with that code:
I compile under XINU.
The next variables are relevant :
unsigned long ularray[];
int num;
char str[100];
There is a function returns int:
int func(int i)
{
return ularray[i];
}
now the code is like this:
num = func(i);
sprintf(str, "number = %lu\n", num);
printf(str);
The problem is I get big numbers while printing with %lu, which is not correct.
If i change the %lu to %d, i get the correct number.
For example: with %lu i get 27654342, while with %d i get 26, the latter is correct;
The variables are given, the declaration of the function is given, i write the body but it must return int;
My questions are:
I'm not familiar with 'sprintf' maybe the problem is there?
I assigned unsigned long to int and then print the int with %lu, is That correct?
How can i fix the problem?
Thanks in advance.
Thanks everyone for answering.
I just want to mention I'm working under XINU, well i changed the order of the compilation of the files and what you know... its working and showing same numbers on %lu and %d.
I'm well aware that assigning 'unsigned long' to int and then printing with %lu is incorrect coding and may result loss of data.
But as i said, the code is given, i couldn't change the variables and the printing command.
I had no errors or warnings btw.
I have no idea why changing the compilation order fixed the problem, if someone have an idea you are more then welcome to share.
I want to thank all of you who tried to help me.
I assigned unsigned long to int and then print the int with %lu, is That correct?
No, it isn't correct at all. Think about it a bit! Printf tries to access the memory represented by the variables you pass in and in your case, unsigned long is represented on more bits than int, hence when printf is told to print an unsigned int, it'll read past your actual int and read some other memory which is probably garbage, hence the random numbers. If printf had a prototype mentioning an unsigned long exactly, the compiler could perform an implicit cast and fill the rest of the unwanted memory with zeroes, but since it's not the case, you have to do either one of these solutions:
One, explicit cast your variable:
printf("%lu", (unsigned long)i);
Two, use the correct format specifier:
printf("%d", i);
Also, there are problems with assigning an unsigned long to an int - if the long contains a too big number, then it won't fit into the int and get truncated.
1) the misunderstanding is format specifiers in general
2) num is an int -- therefore, %d is correct when an int is what you want to print.
3) ideally
int func(int i) would be unsigned long func(size_t i)
and int num would be unsigned long num
and sprintf(str, "number = %d\n", num); would be sprintf(str, "number = %lu\n", num);
that way, there would be no narrowing and no conversions -- the type/values would be correctly preserved throughout execution.
and to be pedantic, printf should be printf("%s", str);
if you turn your warning levels way up, your compiler will warn you of some of these things. i have been programming for a long time, and i still leave the warning level obnoxiously high (by some people's standards).
If you have an int, use %d (or %u for unsigned int). If you have a long, use %ld (or %lu for unsigned long).
If you tell printf that you're giving it a long but only pass an int, you'll print random garbage. (Technically that would be undefined behavior.)
It doesn't matter if that int somehow "came from" a long. Once you've assigned it to something shorter, the extra bytes are lost. You only have a int left.
I assigned unsigned long to int and then print the int with %lu, is That correct?
No, and I suggest not casting to int first or else simply using int as the array type. It seems senseless to store a much larger representation and only use a smaller one. Either way, the sprint results will always be off until you properly pair the type (technically the encoding) of the variable with the format's conversion specifier. This means that if you pass an unsigned long, use %ul, if it's an int, use either %i or %d (the difference is that %d is always base-10, %i can take additional specifiers to print in other bases.
How can I fix the problem?
Change the return of your func and the encoding of num to unsigned long
unsigned long ularray[];
unsigned long num;
char str[100];
unsigned long func(int i)
{
return ularray[i];
}

Convert int to double

I ran this simple program, but when I convert from int to double, the result is zero. The sqrt of the zeros then displays negative values. This is an example from an online tutorial so I'm not sure why this is happening. I tried in Windows and Unix.
/* Hello World program */
#include<stdio.h>
#include<math.h>
main()
{ int i;
printf("\t Number \t\t Square Root of Number\n\n");
for (i=0; i<=360; ++i)
printf("\t %d \t\t\t %d \n",i, sqrt((double) i));
}
Maybe this?
int number;
double dblNumber = (double)number;
The problem is incorrect use of printf format - use %g/%f instead of %d
BTW - if you are wondering what your code did here is some abridged explanation that may help you in understanding:
printf routine has treated your floating point result of sqrt as integer. Signed, unsigned integers have their underlying bit representations (put simply - it's the way how they are 'encoded' in memory, registers etc). By specifying format to printf you tell it how it should decipher that bit pattern in specific memory area/register (depends on calling conventions etc). For example:
unsigned int myInt = 0xFFFFFFFF;
printf( "as signed=[%i] as unsigned=[%u]\n", myInt, myInt );
gives: "as signed=[-1] as unsigned=[4294967295]"
One bit pattern used but treated as signed first and unsigned later. Same applies to your code. You've told printf to treat bit pattern that was used to 'encode' floating point result of sqrt as integer. See this:
float myFloat = 8.0;
printf( "%08X\n", *((unsigned int*)&myFloat) );
prints: "41000000"
According to single precision floating point encoding format.
8.0 is simply (-1)^0*(1+fraction=0)*2^(exp=130-127)=2*3=8.0 but printed as int looks like just 41000000 (hex of course).
sqrt() return a value of type double. You cannot print such a value with the conversion specifier "%d".
Try one of these two alternatives
printf("\t %d \t\t\t %f \n",i, sqrt(i)); /* use "%f" */
printf("\t %d \t\t\t %d \n",i, (int)sqrt(i)); /* cast to int */
The i argument to sqrt() is converted to double implicitly, as long as there is a prototype in scope. Since you included the proper header, there is no need for an explicit conversion.

greater integer width

i m trying to enter a five digit number greater than 32767 and i used "unsigned" while declaring int number, and when i m trying to print the same number it prints some arbitary negative number,
results get overflowed......
pls help me out
Without seeing your code, I am guessing you are using %d or %i in the printf statement. Use %u instead.
Print unsigned values using "%u" instead of "%d".
Until you show some of the code, I can't be sure of anything.
But AFAIK you shouldn't be able to print out a negative number if you're printing out an uint – even if it overflows, the integer will always hold a positive number, as far as C is concerned.
So there's something else wrong.
Use correct format specifier.
%d for int
%u for unsigned int.
Using incorrect format specifier in printf() may cause Undefined Behavior.
For example, the following code invokes Undefined Behavior(UB).
#include<stdio.h>
int main(void)
{
unsigned int z=Some_value; /*Some_value is an unsigned int */
printf("%d",z);
/*UB as format specifier for unsigned int is incorrect,it should be %u not %d*/
}
I guess int is 16bit on your machine/compiler.
Though I don't know what your platform is, I guess that long would solve your problem (it is 32bit or more on all platforms I know). Print it with %ld instead of %d.
Don't get tempted to use unsigned and %u, because they will just give you numbers up to 65536, and I guess that you want more.

Resources