I was reading a book and came across a program to read entries from a /proc file.
The program which they mentioned has following line
printf("%.*s", (int) n, line);
I am not clear with meaning of above line
what type of print if above "%.*s used instead of %s
The code can be read here
Abstract from here:
.* - The precision is not specified in
the format string, but as an
additional integer value argument
preceding the argument that has to be
formatted.
So this prints up to n characters from line string.
The cast expression (int) n converts the value of n to type int. This is because the formatting specifier requires a plain int, and I assume (since you didn't include it) the variable n has a different type.
Since a different type, like size_t might have another size, it would create problems with the argument passing to printf() if it wasn't explicitly converted to int.
Related
In function with variable number of arguments, the "first argument" is "total number of arguments" being passed. But in printf() we never mention argument count. So how does it get to know about the total argument list ? How does printf() works ?
Let's look on printf declaration structure:
int printf(const char *format, ...)
format is actually the string that contains the text to be written to stdout.
The contained embedded format tags are later replaced by the values specified in subsequent additional arguments, and format is set accordingly as required.
You don't supply an argument count to printf - You do supply a format string, however - And that specifies how many arguments printfshould expect.
Very roughly speaking, the number of % signs in the format string is the argument count (although reality is a bit more complicated).
Conversion specifiers in the format string tell printf the number and types of arguments it should expect - for example, the format string "there are %d vowels in %s\n" tells printf to expect two arguments in addition to the format string, the first one being type int and the second being char *.
It's up to you to make sure the arguments match up with the format string. If you don't pass enough arguments, or the argument types don't match what the format string expects, then the behavior is undefined (most likely garbled output or a runtime error). If you pass too many arguments, the additional arguments are evaluated, but otherwise the function will operate normally as long as the format string is satisfied.
Edit
Chapter and verse
7.21.6.1 The fprintf function
...
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 am trying to convert a string read using wscanf to an integer using wcstol, both from header file wchar.h on Linux. While wcstol works on constant wide-char strings (e.g. L"23") it does not work on wscanf input, which puzzles me. I always get 0, even if the input is actually numeric (e.g. 23). Why?
$ ./test
23
s=23
0
Here is my test program:
#include <stdio.h>
#include <wchar.h>
int main() {
wchar_t s[100];
if (wscanf(L"%s", s) == 1) {
wprintf(L"s=%s\n", s);
wprintf(L"%ld\n", wcstol(s, NULL, 10));
}
}
If instead of wcstol I use strtol, it works but I get this warning:
/usr/include/stdlib.h:183:17: note: expected ‘const char * restrict’ but argument is of type ‘wchar_t * {aka int *}’
which I could silent using a type cast. I thought wcstol was the right way to parse a wide-char string to an integer. Since on my machine chars are actually ints, strtol happens to work, but that leaves me still unsure whether this is the right solution. What's going on here? Why wcstol does not do its job?
Your problem is with the wscanf() format. A %s field descriptor designates a pointer to char, just like for scanf(). These two functions differ a bit in how they convert the input, but they agree on the meaning of the field descriptors.
For reading into an array of wchar_t, you want %ls. Moreover, whether you should use wscanf() of scanf() is primarily a function of how the input is encoded, not of the data type into which you want to scan its contents.
Your problem is the wscanf format.
As described on MAN:
s
Matches a sequence of non white-space wide characters. [...] The application shall ensure that the corresponding argument is a pointer to a character array large enough to accept the sequence and the terminating null character, which shall be added automatically.
Simply "%s" must be used for non-wide-chars string, as usual in printf, scanf and so on
MAN also says:
l (ell)
Specifies that a following d, i, o, u, x, X, or n conversion specifier applies to an argument with type pointer to long or unsigned long; [...] that a following c, s, or [ conversion specifier applies to an argument with type pointer to wchar_t.
That means you must use "%ls" as format string to read a wide-char string.
There is another non-standard ISO C solution if you are on POSIX or on .NET MSDN: format "%S" can be used.
Whenever I send in a number from the command line it errors and gives me a wrong number
edgeWidth=*argv[2];
printf("Border of %d pixels\n", edgeWidth);
fileLocation=3;
./hw3 -e 100 baboon.ascii.pgm is what I send in through the command line and when I print the number to the screen I get 49 as the number
int edgeWidth is defined at the beginning of the program.
Why is it not giving me 100?
argv contains an array of strings. So argv[1] is a string, you need to convert it to an integer:
edgeWidth = atoi(argv[1]);
The problem is that by doing
edgeWidth = *argv[2];
you're assigning the first character of "100" to edgeWidth. 49 happens to be the ASCII value for '1'.
If you want 100, you need to use something like atoi or strtol to parse the string into an int.
Addendum: Regarding numeric promotion, part two of 6.5.16.1 in the C99 spec states:
In simple assignment (=), the value of the right operand is converted
to the type of the assignment expression and replaces the value stored
in the object designated by the left operand.
so it does appear that numeric promotion happens here.
Because command line arguments are by default as char* (or may be char** somewhere) not int. you need proper conversion like atoi() to use it as int.
You should use edgeWidth = atoi(argv[2]) to get expected output.
What is the function definition of the printf() function as defined in the standard C library?
I need the definition to solve the following question:
Give the output of the following:
int main()
{
int a = 2;
int b = 5;
int c = 10;
printf("%d ",a,b,c);
return 0;
}
The C language standard declares printf as follows:
int printf(const char *format, ...);
It returns an integer and takes a first parameter of a pointer to a constant character and an arbitrary number of subsequent parameters of arbitrary type.
If you happen to pass in more parameters than are required by the format string you pass in, then the extra parameters are ignored (though they are still evaluated). From the C89 standard §4.9.6.1:
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.
You pass an array of chars (or pointer) as the first argument (which includes format placeholders) and additional arguments to be substituted into the string.
The output for your example would be 2 1 to the standard output. %d is the placeholder for a signed decimal integer. The extra space will be taken literally as it is not a valid placeholder. a is passed as the first placeholder argument, and it has been assigned 2. The extra arguments won't be examined (see below).
printf() is a variadic function and only knows its number of additional arguments by counting the placeholders in the first argument.
1 Markdown does not allow trailing spaces in inline code examples. I had to use an alternate space, but the space you will see will be a normal one (ASCII 0x20).
Its
int printf(const char *format, ...);
format is a pointer to the format string
... is the ellipsis operator , with which you can pass variable number of arguments, which depends on how many place holders we have in the format string.
Return value is the number of characters that were printed
Have a look here about the ellipsis operator: http://bobobobo.wordpress.com/2008/01/28/how-to-use-variable-argument-lists-va_list/
man 3 printf gives...
int printf(const char *restrict format, ...);
Writes to the standard output (stdout) a sequence of data formatted as the format argument specifies. After the format parameter, the function expects at least as many additional arguments as specified in format.
%d = Signed decimal integer
printf("%d ",a,b,c);
For every %(something) you need add one referining variable, therefore
printf("%d ",a+b+c); //would work (a+b+c), best case with (int) before that
printf("%d %d %d",a,b,c); //would print all 3 integers.
What's going on here:
printf("result = %d\n", 1);
printf("result = %f\n", 1);
outputs:
result = 1
result = 0.000000
If I ensure the type of these variables before trying to print them, it works fine of course. Why is the second print statement not getting implicitly converted to 1.00000?
In the second case you have a mismatch between your format string and the argument type - the result is therefore undefined behavio(u)r.
The reason the 1 is not converted to 1.0 is that printf is “just” a C function with a variable number of arguments, and only the first (required) argument has a specified type (const char *). Therefore the compiler “cannot” know that it should be converting the “extra” argument—it gets passed before printf actually reads the format string and determines that it should get a floating point number.
Now, admittedly your format string is a compile-time constant and therefore the compiler could make a special case out of printf and warn you about incorrect arguments (and, as others have mentioned, some compilers do this, at least if you ask them to). But in the general case it cannot know the specific formats used by arbitrary vararg functions, and it's also possible to construct the format string in complex ways (e.g. at runtime).
To conclude, if you wish to pass a specific type as a “variable” argument, you need to cast it.
An undefined behavior. An int is being treated as float
The short answer is that printf isn't really C++. Printf is a C function which takes a variable argument list, and applies the provided arguments to the format string basis the types specified in the format string.
If you want any sort of actual type checking, you should use streams and strings - the actual C++ alternatives to good old C-style printf.
Interesting, presumably it's fine if your put '1.0'
I suppose the printf only gets the address of the variable, it has no way of knowing what it was. But I would have thought the compiler would have the decency to warn you.