Can anyone explain the output printf("%0 %x",a);? - c

This code is making me so confused. I can't understand what %0 is doing inside printf!
Code:
#include <stdio.h>
int main() {
int a = 100;
printf("%0 %x", a);
return 0;
}
Output
%x

%0 %x has an invalid printf conversion specification:
the 0 is a flag specifying that the number representation should be padded with initial zeroes to the specified width (which is not specified here)
the is a flag specifying that the signed conversion should be prefixed with a space if positive in the same place as a - for negative numbers.
the second % is the conversion specifier, so the initial part is just a variation of %% with 2 extra flags and thus should cause a % character to be output, but the C Standard specifies in 7.21.6.20 the fprintf function that
%: A % character is written. No argument is converted. The complete conversion specification shall be %%.
Hence %0 % is an invalid conversion specification as % does not accept flags.
Most libraries will just output %x, ie: % for %0 % and x for the trailing x, ignoring the a argument, and this is what you get on your system, but the behavior is actually undefined, so nothing can be assumed.
Conversely, printf("|%0 5d|", 100); will output | 0100| but the space is ignored for the x conversion which is unsigned so printf("|%0 5x|", 100); will output |00064|.

Related

printf: why doesn't %x print leading 0x (as opposed to %a)?

This code:
#include <stdio.h>
int main(void)
{
printf("%a\n", 1.0);
printf("%x\n", 93);
}
outputs:
0x1p+0
5d
Why not 0x5d?
Does someone know the rationale?
Note: this question is not exactly the same since it is about %#x.
Reason of the question: for %x cannot always "feed it back to C in initializer":
$ cat t324.c
#include <stdio.h>
int main(void)
{
printf(X);
}
$ gcc t324.c -DX="\"double x = %a;\", 10.0" && ./a.exe | gcc -xc - -c
<nothing>
$ gcc t324.c -DX="\"int x = %x;\", 10" && ./a.exe | gcc -xc - -c
<stdin>:1:9: error: ‘a’ undeclared here (not in a function)
"%a", "%A" leads with "0x", "0X" to help distinguish it from decimal output of "%f", "%e", "%g", "%F", ...
Note "%a" instead of say "%e", affect 2 parts, the prefix and the base letter: "0x" and "p" instead of "" and "e".
"%a" came along well after memory prices dropped.
"%x" leads without a prefix as often code needs to concatenate hex output as in printf("%08x%08x", a32, b32); It is trivial to prefix with "0x" then as in "0x%08x%08x". Not prefixing hex output as the default was certainly more common, back in the day (1970s) as every bytes costs.
Using # with "%x" as in "%#x" does not always prefix output. The prefix occurs (in the same case as digits) when the value is non-zero.
For clarity, I find a lower case x and uppercase hex digits useful.
// v------ lower --------v
printf("0x%08X\n", 0u-1u); // 0xFFFFFFFF
// ^-- upper ---------^^^^^^^^
I think you just have option to have 0x or not. When you use %x, you receive the raw hexadecimal number. But when you use %#x, you receive the hex number with the 0x prefix. What you choose depends on situation.
As explained by #Jack05, the '#' character makes the difference. The manual of printf explains the conversion:
Each conversion specification is introduced by the character %, and ends with
a conversion specifier. In between there may be (in this order) zero or more
flags, an optional minimum field width, an optional precision and an optional
length modifier.
The overall syntax of a conversion specification is:
%[$][flags][width][.precision][length modifier]conversion
If the flag character is set with '#', then:
For x and X conversions, a nonzero result has the string
"0x" (or "0X" for X conversions) prepended to it.
For the 'a' or 'A' conversion,
the double argument is converted to hexadecimal notation
(using the letters abcdef) in the style [-]0xh.hhhhp±d;
for A conversion the prefix 0X, the letters ABCDEF

Why format specifier %d or %i does not work for a double variable but %f works and print a float output of an integer variable?

Must we always use %f to printf a %d value, and %lf to take input by scanf ? Why format specifier %d or %i does not work for a double variable but %f works and print a float output of an integer variable?
Is it always safe to declare double and take input scanf with %lf and printf as %f?
My codes:
int main(void)
{
double dnum = 7777;
printf(" %f \n", dnum);
return 0;
}
output is 7777.000000
int main(void)
{
double dnum = 7777;
printf(" %i \n", dnum);
return 0;
}
Output is 0
int main(void)
{
double dnum = 7777;
printf(" %d \n", dnum);
return 0;
}
Output is 0
Format and data mismatch in printf() invokes undefine behavior.
In your code, the type of dnum is double regardless of its actual value, which may be an integer.
%f can be used to print double, but neithor %d nor %i cannot be used.
If you want to print double, you should use %g, %f or %e depending on the format that you want it to be printed.
%d is the same as %i (for printf) and it goes along with signed integer.
The format specifier: %d or %i expects the argument of signed int, if anything else is given in the formatted printf() statement, such as:
float f = 1.50235F;
printf("%d", f);
Will expect for signed int, if you pass a float or a double instead, it'll tend to undefined behavior and probably print 0.
In a more practical sense, if you want to do-it-yourself, you may add -Wformat flag and run the command in your command prompt or any command shell:
$ gcc -o main main.cpp -Wformat
Then you'll get a warning generated by the compiler similar to the following:
main.c: In function 'int main()':
main.c:9:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'double' [-Wformat=]
9 | printf("%d\n", d);
| ~^ ~
| | |
| int double
| %f
The double has the twice precision than a float could hold (i.e. double has 15 decimal digits of precision, while float has only 7. So, the %f type specifier could be used for double in this case too.)
To know further about the format specifiers: List of all format specifiers in C.
All conversion specifiers expect their corresponding argument to be a specific type; you can't arbitrarily mix and match them. %d and %i expect their corresponding argument to have type int - if it doesn't, the behavior is undefined and you'll (usually) get weird output. Integers and floating point values have very different binary representations and may have different sizes - most modern platforms use 32 bits to store integer values and 64 bits to store doubles, which affects how those values are interpreted in the printf code.
For an authoritative list of conversion specifiers and the types of arguments they take, refer to the C 2011 Online Draft, section 7.21.6.1 (The fprintf function).
Welcome in the world of undefined behavior!
To use the %d conversion specifier to print a double value or the %f conversion specifier to print an int value invokes undefined behavior.
%f is furthermore meant to print a value of type double, not float. A passed float gets automatically promoted.
The C standard states:
If a conversion specification is invalid, the behavior is undefined.288) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Source: C18, 7.21.6.1/9
d,i - The int argument is converted to signed decimal in the style[-]dddd. The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it is expanded with leading zeros. The default precision is 1. The result of converting a zero value with a precision of zero is no characters.
......
f,F - A double argument representing a floating-point number is converted to decimal notation in the style[-]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is zero and the flag is not specified, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.
A double argument representing an infinity is converted in one of the styles[-]infor[-]infinity— which style is implementation-defined. A double argument representing a NaN is converted in one of the styles[-]nanor[-]nan(n-char-sequence)— which style, and the meaning of any n-char-sequence, is implementation-defined. The F conversion specifier produces INF,INFINITY, or NAN instead of inf, infinity, or nan, respectively.283)
Source: C18, §7.21.6.1/8
Summary:
Except for the first example, The output you get is any arbitrary value (unless the implementation didn't specified what happens else). It doesn't "work" in the one way nor in the other.

Why only multiple "%" is accepted by printf?

Following program give the output %%. Why?
#include <stdio.h>
int main() {
//code
printf("%%%%");
return 0;
}
output:
%%
TL;DR a % is a valid conversion specifier for printf().
Quoting C11, chapter §7.21.6.1, for conversion specifiers,
Each conversion specification is introduced by the character %. After the %, the following
appear in sequence:
.....
— A conversion specifier character that specifies the type of conversion to be applied.
and, from paragraph 8, for % as a conversion specifier character
for % conversion specifier
% A % character is written. No argument is converted. The complete
conversion specification shall be %%.
Your code has a pair of %%s.
Printf function's first argument is a format represented by a char*, it's not a string.
That's why for printing an int,for example, you have to write "%d". So % is a special character, if you only write % as format, the compiler won't be happy because it is waiting for something after the % (either d, p, x, s, f, ...).
However, by writing %% it means "Print me one escaped %". That's why %%%% prints %%
EDIT: If you want a function that prints exactly what you give, you can use write:
char* mystr = "%%%%";
write(STDOUT_FILENO, mystr, strlen(mystr));

understanding weird output of printf function

According to me
int a=0;
printf("%d",a);
works same as
char *ptr="%d"
ptr points to % and then ptr reads the whole string from % and 4 bytes are read from memory.
Now consider the below code
printf("%d"+1,a); //value of a=0
is same as
char *ptr="%d"
ptr+=1;
ptr now points to d and so string from d is printed
Now
printf(1+"Alex"); //prints lex
ptr points l and prints string from there on....
Now what will happen in the following cases?It appears to be out of my scope.
printf("%",a);
printf("%%%%");
printf("%%d",a);
printf("%",a); does not have a valid conversion specifier, so it is covered by:
§7.21.6.1
9 If a conversion specification is invalid, the behavior is
undefined. If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
printf("%%%%"); will simply print %%, since %% is a conversion specifier. See the printf man pages.
%
A '%' is written. No argument is converted. The complete conversion
specification is '%%'.
As mentioned in the comments, printf("%%d",a); is probably not undefined behavior. %% becomes % and the a is ignored.
§7.21.6.1
2 The fprintf function writes output to the stream pointed to by stream,
under control of the string pointed to by format that specifies how
subsequent arguments are converted for output. If there are
insufficient arguments for the format, the behavior is undefined. If
the format is exhausted while arguments remain, the excess arguments
are evaluated (as always) but are otherwise ignored. The fprintf
function returns when the end of the format string is encountered.
I hope that this quote from the C Standard will help you
8 The conversion specifiers and their meanings are:
% A % character is written. No argument is converted. The complete
conversion specification shall be %%.
For example
printf("%%%%");
will output
%%

What does "%.*s" mean in printf?

I got a code snippet in which there is a
printf("%.*s\n")
what does the %.*s mean?
You can use an asterisk (*) to pass the width specifier/precision to printf(), rather than hard coding it into the format string, i.e.
void f(const char *str, int str_len)
{
printf("%.*s\n", str_len, str);
}
More detailed here.
integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)
. followed by integer number or *, or neither that specifies precision
of the conversion. In the case when * is used, the precision is
specified by an additional argument of type int. If the value of this
argument is negative, it is ignored. If neither a number nor * is
used, the precision is taken as zero. See the table below for exact
effects of precision.
So if we try both conversion specification
#include <stdio.h>
int main() {
int precision = 8;
int biggerPrecision = 16;
const char *greetings = "Hello world";
printf("|%.8s|\n", greetings);
printf("|%.*s|\n", precision , greetings);
printf("|%16s|\n", greetings);
printf("|%*s|\n", biggerPrecision , greetings);
return 0;
}
we get the output:
|Hello wo|
|Hello wo|
| Hello world|
| Hello world|
I don't think the code above is correct but (according to this description of printf()) the .* means
The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted.'
So it's a string with a passable width as an argument.
See: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
.* The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted.
s String of characters

Resources