difference in value of uint16_t with printf - c

The output of below program is confusing.
uint16_t first = 10, second = 20, third = 30;
// printf("%p\n", &first);
scanf("%d", &second); // "%d" used intentionally.
printf("%" SCNu16 " ", first);
printf("%" SCNu16 " ", second);
printf("%" SCNu16 "\n", third);
With first printf commented I get 10 20 0. (The "%d" in scanf might be causing this. It works fine if I use "%" SCNu16 in place of %d).
With first printf uncommented I get 0 20 30.
Confusion is - why is printf causing the difference in output? This is a consistent behavior.

In your code,
scanf("%d", &second);
is undefined behavior. %d expects the argument to be a pointer to a signed integer type (int).
Quoting C11, chapter §7.21.6.2, fscanf function
[...] Unless assignment suppression was indicated by a *, the
result of the conversion is placed in the object pointed to by the first argument following
the format argument that has not already received a conversion result. If this object
does not have an appropriate type, or if the result of the conversion cannot be represented
in the object, the behavior is undefined.
That said, SCNuN macro is for fscanf family, fprintf() family has the counterpart as PRIuN.

If it is a "consistent behavior" or not depends on your definition of it. I get the same behavior when I run your code, but it does not change the fact that you have undefined behavior in your program.
I tried compiling it with -O3 and then I got the output 10 20 30 when giving the input 20, both with and without the said printf statement.
So while it could be fun to speculate about why your code behaves the way it does, it is not very meaningful. The code is invalid, so you have no guarantees.
I also tried switching the order of variable declaration: uint16_t third=30, second=20, first=10; The behavior changed, although it should not if the code were valid.

Related

Why compiler is not issuing error while passing an int (not int *) as the argument of scanf()?

I tried the below c program & I expected to get compile time error, but why compiler isn't giving any error?
#include <stdio.h>
#include <conio.h>
int main()
{
int a,b;
printf("Enter a : ");
scanf("%d",&a);
printf("Enter b : ");
scanf("%d",b);
printf("a is %d and b is %d\n",a,b);
getch();
return 0;
}
I am not writing & in scanf("%d",b). At the compile time , compiler don't give any error but during execution value of b is 2686792(garbage value).
As per C11 standard, Chapter §6.3.2.3
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
So, the compiler will allow this, but the result is implementation-defined.
In this particular case, you're passing b to scanf() as an argument, which is uninitialized, which will cause the program to invoke undefined behaviour, once executed.
Also, printf() / scanf() being variadic functions, no check on paramater type is perforfmed in general, unless asked explicitly through compiler flag [See -Wformat].
It is not a a compile time error but a runtime issue.
The compiler expects that you have given a valid address to scan the value to, during runtime only it will come to know whether the address is valid or not .
If you try to scan the value to invalid address it leads to undefined behavior and might see a crash.
It scans fine because scanf expects a memory location in its argument. That's why we use & to give memory location of the corresponding variable.
In your case scanf just scans the entered value and puts it in the memory location which has the value of b(instead of scanning and putting it in the memory location where b is stored).
The & operator in C returns the address of the operand. If you give just the b without the & operator, it will be passed by value and the scanf won't be able to set the value. This would result in unexpected behaviour as you already noticed. It has no way of verifying the address before the runtime and hence you won't notice the issue until runtime.

why array shows garbage value when only one format specifier used?

i am trying to print value of an array in C-language.I am using 3 format specifier for only one value of array , my problem is that i don't understand that how other two values are coming in my output .
here is my code:
int arr[6] = {3,4,42,2,77,8};
printf("%d %d %d ",arr[2]);
output :
42 3 4
According to the C Standard
If there are insufficient arguments for the format, the behavior is
undefined.
In your call of printf
printf("%d %d %d ",arr[2]);
the arguments are exhausted after the first format specjfjer. So the function call has undefined behaviour and the output can contain any garbage.
You shall write
printf( "%d ", arr[2] );
or for example
printf( "%d %d %d ", arr[2], arr[3], arr[4] );
When printf() sees three format specifiers, it looks at specific locations, either in stack memory or in CPU registers, depending on the conventions of the compiler, for three arguments.
You provided one, but some data that you have no control over exists in the other two locations, and that's what gets printed.
The other two values are garbage and don't have any meaning. The function printf requires as many arguments as there are format specifiers, so in your case three. Since you only provided one argument (arr[2]), the other two specifier 'don't know' what to print - thus gargabe will come out. Make sure to provide the required number of arguments.
If you want to print the array number by number, you will have to use a for loop.
The signature of printf is.
int printf(char*, ...);
So, you can have a variable number of arguments, then.
printf("%d %d %d ",arr[2]);
Is a valid call of the function printf.
However, because you provided no values ​​yourself, then you will get whatever... that in your special case it seems that it printed arr[0] and arr[1].

Undefined behaviour of the compiler

Hey what will be the the output of the following code, it is not working as it should.
int j=65;
printf("j>=65?%d:%c",j);
In this case it should print: j>=65, and then match the next %d with the j so print 65, and then %c is printing l how the l is printed.
Instead of
Printf("j>=65?%d:%c",j);
there has to be at least
printf("j>=65?%d:%c",j);
The code has undefined behaviour because the number of format specifiers is greater than the number of following arguments.
I think you mean the following
printf( j >= 65 ? "%d" : "%c", j );
in this case there will be outputed 65.
The format specifier "j>=65?%d:%c" has two %... pieces, they indicate that two values are to be printed. The format is used within printf("j>=65?%d:%c",j); which only provides one value to be printed.
There is no checking in C that the printf is given the correct number of arguments for the format, there is no protection at run time for what actually happens when too few arguments are given. That is undefined behaviour. The C language allows the programmer to write many things that lead to undefined behaviour.
You should not use conditional operation inside double quotes like this printf("j>=65?%d:%c",j);. you are having two format specifier and only one argument. so it results in undefined behavior. so j>=65? is printed first, %d prints 65, %c expects arguments, but there is no arguments, so it prints anything. Results in undefined behavior. You should use No of arguments equal to the no of format specifiers.
When i run your code in my system i got-
root#ubuntu:~/c/basics# cc con1.c
con1.c: In function ‘main’:
con1.c:6:1: warning: format ‘%c’ expects a matching ‘int’ argument [-Wformat=] // see this warning
printf("j>=65?%d:%c",j);
^
root#ubuntu:~/c/basics# ./a.out
j>=65?65:� // see this undefined symbol
Try the following change and fix it-
printf(j>=65 ? "%d" : "%c",j);
when the condition is true it prints 65 and when condition fails it prints the character(For that input value)
or
j>=65 ? printf("%d",j) : printf("%c",j);
You call printf() with two format specifiers, but pass only one parameter after the format string. The function doesn't know how many parameters you pass, so it assumes you did pass two arguments. The result is, it reads the random garbage that just happens to be at the memory location where would be the second parameter if you did pass it. Run it another day, compile it with different compiler or different options, and you get different result (in worst case, segmentation fault).

What is the difference between %d and %*d in c language?

What is %*d ? I know that %d is used for integers, so I think %*d also must related to integer only? What is the purpose of it? What does it do?
int a=10,b=20;
printf("\n%d%d",a,b);
printf("\n%*d%*d",a,b);
Result is
10 20
1775 1775
The %*d in a printf allows you to use a variable to control the field width, along the lines of:
int wid = 4;
printf ("%*d\n", wid, 42);
which will give you:
..42
(with each of those . characters being a space). The * consumes one argument wid and the d consumes the 42.
The form you have, like:
printf ("%*d %*d\n", a, b);
is undefined behaviour as per the standard, since you should be providing four arguments after the format string, not two (and good compilers like gcc will tell you about this if you bump up the warning level). From C11 7.20.6 Formatted input/output functions:
If there are insufficient arguments for the format, the behavior is undefined.
It should be something like:
printf ("%*d %*d\n", 4, a, 4, b);
And the reason you're getting the weird output is due to that undefined behaviour. This excellent answer shows you the sort of things that can go wrong (and why) when you don't follow the rules, especially pertaining to this situation.
Now I wouldn't expect this to be a misalignment issue since you're using int for all data types but, as with all undefined behaviour, anything can happen.
When used with scanf() functions, it means that an integer is parsed, but the result is not stored anywhere.
When used with printf() functions, it means the width argument is specified by the next format argument.
The * is used as an indication that the width is passed as a parameter of printf
in "%*d", the first argument is defined as the total width of the output, the second argument is taken as normal integer.
for the below program
int x=6,p=10;
printf("%*d",x,p);
output: " 10"
the first argument ta passed for *, that defines the total width of the output... in this case, width is passed as 6. so the length of the entire output will be 5.
now to the number 10, two places are required (1 and 0, total 2). so remaining 5-2=3 empty string or '\0' or NULL character will be concatenated before the actual output

What does %0x%x mean in C/C++ programming?

I have the following code, but I'm not sure what %0x%x means in the following code?
sprintf(buf, "pixel : %0x%x \n", gpbImageData[100]);
OutputDebugString(buf);
gpbImageData[100] is pointing to an image data in the memory.
Your example causes undefined behaviour. The format string will cause sprint to expect two int values:
%0x
%x
Both of these mean exactly the same thing - print a value as a hexadecimal number. However, the call you've shown passes only one argument.
Are you sure it doesn't say 0x%x? If it doesn't, it's probably supposed to... that would be more normal, and will print the passed-in value as a hexadecimal number prefixed with 0x.
Your code as shown should cause a warning. clang gives:
example.c:5:15: warning: more '%' conversions than data arguments [-Wformat]
printf("%0x%x\n", 125987);
~^
1 warning generated.
and gcc says:
example.c: In function ‘main’:
example.c:5: warning: too few arguments for format
example.c:5: warning: too few arguments for format
Both without providing any flags at all.
You certainly meant this format string "0x%x"
sprintf(buf, "pixel : 0x%x \n", gpbImageData[100]);
This adds the 0x prefix to the hexadecimal numbers when they are written in buf.
Note that you can achieve the same thing with the flag character #:
sprintf(buf, "pixel : %#x \n", gpbImageData[100]);
The correct format is "0x%x" as ouah and Carl Norum said. Whatever gpbImageData[100] content (pointer or number), %x will print its value as a hexadecimal number. 0x is just a text. Maybe "gpbImageData" is an array of pointers.

Resources