I'm stuck fixing ancient code, and here is today's issue:
output_file_status = fprintf ( data_file, "%03d%08s%+014.2f%06.3f%",
LongValue, CharStarValue, Double1, Double2 );
Lint32 produces: Lint32 results in “malformed format string”
1) Do you all agree the format string can not end in a % sign? I don't believe a standalone % has meaning.
2) When I either remove the trailing %, or append an additional %, I still get the same warning.
This is using the Oracle Pro*C compiler (so the CharStarValue is actually a (char*)VarChar.arr ).
Yes, you are correct that % by itself at the end is an error. It should be %% to produce one literal % in the formatted output.
It might be that your linter is also complaining about the use of %03d with a long value. That should be %03ld.
Taking it piece by piece:
"%03d" expects an int. OP supplies a LongValue. With a long, specifier should be "%03ld".
"%08s" expects a pointer to char. OP supplies CharStarValue. OK. But the "0" in the specifier is undefined behavior for a %s. Recommend "%8s"
"%+014.2f" expects a double. OK. Flags '+', '0' are OK.
"%06.3f" expects a double. OK. Flags '+', '0' are OK.
"%" should have something after it else behavior is undefined. Recommend removal or "%%".
To OP's 2 points
1 A proper format should not end with a lone %, but may end with paired %%s.
A standalone % introduces "If a conversion specification is invalid, the behavior is undefined" C11 7.21.6.1 9.
2 To get rid of all warnings, try "%03ld%8s%+014.2f%06.3f".
Related
While compiling the following code:
#include <stdio.h>
int main() {
printf("99% Invisible");
return 0;
}
in gcc 7.5.0 I get the following warnings:
test.c: In function ‘main’:
test.c:4:16: warning: ' ' flag used with ‘%n’ gnu_printf format [-Wformat=]
printf("99% Invisible");
^
test.c:4:16: warning: 'I' flag used with ‘%n’ gnu_printf format [-Wformat=]
test.c:4:16: warning: format ‘%n’ expects a matching ‘int *’ argument [-Wformat=]
printf("99% Invisible");
~~~^
What is going on here? I don't see mention of a " " flag or an "I" flag anywhere in documentation. The code outputs 99visible, essentially ignoring the space and I in the format string and following the %n format.
edit: People seem to be misunderstanding the question. I know how to printf a literal %, and what %n do. I am just curious what is happening here.
(also, for those who know the context: I know the system in question didn't use C, I am just curious as to what printf is doing here).
The I flag is a GNU extension to printf. From the man page:
glibc 2.2 adds one further flag character.
I
For decimal integer conversion (i, d, u) the output uses the
locale's alternative output digits, if any. For example, since glibc
2.2.3 this will give Arabic-Indic digits in the Persian ("fa_IR") locale.
So when the compiler checks the format string, it sees % In as a format specifier, i.e. the space and I flags applied to the n conversion specifier. Since neither flag is applicable to the n conversion specifier, the compiler emits a warning for each.
To print the literal %, you must write %%.
https://en.cppreference.com/w/c/io/fprintf
I flag is not in the C standard.
It appears that with your compiler when a % character is encountered in a printf format string, it scans forward to find a valid format specifier, then interprets everything in-between as a modifier. If those are not valid modifiers, an error is flagged.
As others have pointed out, replace "99% Invisible" with "99%% Invisible" to fix the problem.
Perhaps I'm misinterpreting my results, but:
#include <stdio.h>
int
main(void)
{
char buf[32] = "";
int x;
x = scanf("%31[^\0]", buf);
printf("x = %d, buf=%s", x, buf);
}
$ printf 'foo\n\0bar' | ./a.out
x = 1, buf=foo
Since the string literal "%31[^\0]" contains an embedded null, it seems that it should be treated the same as "%31[^", and the compiler should complain that the [ is unmatched. Indeed, if you replace the string literal, clang gives:
warning: no closing ']' for '%[' in scanf format string [-Wformat]
Why does it work to embed a null character in the string literal passed to scanf?
-- EDIT --
The above is undefined behavior and merely happens to "work".
First of all, Clang totally fails to output any meaningful diagnostics here, whereas GCC knows exactly what is happening - so yet again GCC 1 - 0 Clang.
And as for the format string - well, it doesn't work. The format argument to scanf is a string. The string ends at terminating null, i.e. the format string you're giving to scanf is
scanf("%31[^", buf);
On my computer, compiling the program gives
% gcc scanf.c
scanf.c: In function ‘main’:
scanf.c:8:20: warning: no closing ‘]’ for ‘%[’ format [-Wformat=]
8 | x = scanf("%31[^\0]", buf);
| ^
scanf.c:8:21: warning: embedded ‘\0’ in format [-Wformat-contains-nul]
8 | x = scanf("%31[^\0]", buf);
| ^~
The scanset must have the closing right bracket ], otherwise the conversion specifier is invalid. If conversion specifier is invalid, the behaviour is undefined.
And, on my computer running it,
% printf 'foo\n\0bar' | ./a.out
x = 0, buf=
Q.E.D.
This is a rather strange situation. I think there are a couple of things going on.
First of all, a string in C ends by definition at the first \0. You can always scoff at this rule, for example by writing a string literal with an explicit \0 in the middle of it. When you do, though, the characters after the \0 are mostly invisible. Very few standard library functions are able to see them, because of course just about everything that interprets a C string will stop at the first \0 it finds.
However: the string you pass as the first argument to scanf is typically parsed twice -- and by "parsed" I mean actually interpreted as a scanf format string possibly containing special % sequences. It's always going to be parsed at run time, by the actual copy of scanf in your C run-time library. But it's typically also parsed by the compiler, at compile time, so that the compiler can warn you if the % sequences don't match the actual arguments you call it with. (The run-time library code for scanf, of course, is unable to perform this checking.)
Now, of course, there's a pretty significant potential problem here: what if the parsing performed by the compiler is in some way different than the parsing performed by the actual scanf code in the run-time library? That might lead to confusing results.
And, to my considerable surprise, it looks like the scanf format parsing code in compilers can (and in some cases does) do something special and unexpected. clang doesn't (it doesn't complain about the malformed string at all), but gcc says both "no closing ‘]’ for ‘%[’ format" and "embedded ‘\0’ in format". So it's noticing.
This is possible (though still surprising) because the compiler, at least, can see the whole string literal, and is in a position to notice that the null character is an explicit one inserted by the programmer, not the more usual implicit one appended by the compiler. And indeed the warning "embedded ‘\0’ in format" emitted by gcc proves that gcc, at least, is quite definitely written to accommodate this possibility. (See the footnote below for a bit more on the compiler's ability to "see" the whole string literal.)
But the second question is, why does it (seem to) work at runtime? What is the actual scanf code in the C library doing?
That code, at least, has no way of knowing that the \0 was explicit and that there are "real" characters following it. That code simply must stop at the first \0 that it finds. So it's operating as if the format string was
"%31[^"
That's a malformed format string, of course. The run-time library code isn't required to do anything reasonable. But my copy, like yours, is able to read the full string "foo". What's up with that?
My guess is that after seeing the % and the [ and the ^, and deciding that it's going to scan characters not matching some set, it's perfectly willing to, in effect, infer the missing ], and sail on matching characters from the scanset, which ends up having no excluded characters.
I tested this by trying the variant
x = scanf("%31[^\0o]", buf);
This also matched and printed "foo", not "f".
Obviously things are nothing like guaranteed to work like this, of course. #AnttiHaapala has already posted an answer showing that his C RTL declines to scan "foo" with the malformed scan string at all.
Footnote:
Most of the time, an embedded in \0 in a string truly, prematurely ends it. Most of the time, everything following the \0 is effectively invisible, because at run time, every piece of string interpreting code will stop at the first \0 it finds, with no way to know whether it was one explicitly inserted by the programmer or implicitly appended by the compiler. But as we've seen, the compiler can tell the difference, because the compiler (obviously) can see the entire string literal, exactly as entered by the programmer. Here's proof:
char str1[] = "Hello, world!";
char str2[] = "Hello\0world!";
printf("sizeof(str1) = %zu, strlen(str1) = %zu\n", sizeof(str1), strlen(str1));
printf("sizeof(str2) = %zu, strlen(str2) = %zu\n", sizeof(str2), strlen(str2));
Normally, sizeof on a string literal gives you a number one bigger than strlen. But this code prints:
sizeof(str1) = 14, strlen(str1) = 13
sizeof(str2) = 13, strlen(str2) = 5
Just for fun I also tried:
char str3[5] = "Hello";
This time, though, strlen gave a larger number:
sizeof(str3) = 5, strlen(str3) = 10
I was mildly lucky. str3 has no trailing \0, neither one inserted by me nor appended by the compiler, so strlen sails off the end, and could easily have counted hundreds or thousands of characters before finding a random \0 somewhere in memory, or crashing.
Why can a null character be embedded in a conversion specifier for scanf?
A null character cannot directly be specified as part of a scanset as in "%31[^\0]" as the parsing of the string ends with the first null character.
"%31[^\0]" is parsed by scanf() as if it was "%31[^". As it is an invalid scanf()
specifier, UB will likely follow. A compiler may provide diagnostics on more than what scanf() sees.
A null character can be part of a scanset as in "%31[^\n]". This will read in all characters, including the null character, other than '\n'.
In the unusual case of reading null chracters, to determine the number of characters read scanned, use "%n".
int n = 0;
scanf("%31[^\n]%n", buf, &n);
scanf("%*1[\n]"); // Consume any 1 trailing \n
if (n) {
printf("First part of buf=%s, %d characters read ", buf, n);
}
This question already has answers here:
How to escape the % (percent) sign in C's printf
(13 answers)
Closed 8 years ago.
When I run this following code:
#include <stdio.h>
#include <conio.h>
void main(){
clrscr();
printf("%%");
getch();
}
I get % as an output?
What might be the reason behind this logic?
That is what printf does: it is print formatted (f for formatted). It uses % as the formatting character. It is the only reserved character and needs to be escaped to represent it self, i.e. %%. See the manual for more information on formatting: printf.
P.S.: Never use a string that is not a part of the program as the first argument. To print a string message that was input by a user, do printf(%s, message);. Otherwise you will have a security hole in your code.
% comes into format specifiers.
Example
When we write printf("%d", 20);, it will print 20 rather than %d. because the compiler treats % as a format specifier. In the mind of the compiler, the meaning of % is somewhat special.
So if you want that "%" should be the output, then you must write printf("%%"). Here the first % sign will suppress the meaning of the % format specifier and will print % as an output.
From the standard ISO/IEC 9899:1999 (E)
7.19.6.1
Each conversion specification is introduced by the character %.
The conversion specifiers and their meanings are:
% - A % character is written. No argument is converted. The complete
conversion specification shall be %%.
For C printf, % is a special character which typically indicates a parameter to substitute at that position: printf("Hello, %s\n", "World!"); results in "Hello, World!". There are lots of different things you can put after the % depending on the data you want to output. So that leaves the problem of "What if I want to print a percent symbol"?
The solution: Use %%.
The same is true of the special escape character \. "\n" means to print a new line. If you want to actually print the forward slash, you have to put it twice \\
See Printf format string and MSDN.
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.
How do you escape the % sign when using printf in C?
printf("hello\%"); /* not like this */
You can escape it by posting a double '%' like this: %%
Using your example:
printf("hello%%");
Escaping the '%' sign is only for printf. If you do:
char a[5];
strcpy(a, "%%");
printf("This is a's value: %s\n", a);
It will print: This is a's value: %%
As others have said, %% will escape the %.
Note, however, that you should never do this:
char c[100];
char *c2;
...
printf(c); /* OR */
printf(c2);
Whenever you have to print a string, always, always, always print it using
printf("%s", c)
to prevent an embedded % from causing problems (memory violations, segmentation faults, etc.).
If there are no formats in the string, you can use puts (or fputs):
puts("hello%");
if there is a format in the string:
printf("%.2f%%", 53.2);
As noted in the comments, puts appends a \n to the output and fputs does not.
With itself...
printf("hello%%"); /* like this */
Use a double %%:
printf("hello%%");
Nitpick:
You don't really escape the % in the string that specifies the format for the printf() (and scanf()) family of functions.
The %, in the printf() (and scanf()) family of functions, starts a conversion specification. One of the rules for conversion specification states that a % as a conversion specifier (immediately following the % that started the conversion specification) causes a '%' character to be written with no argument converted.
The string really has 2 '%' characters inside (as opposed to escaping characters: "a\bc" is a string with 3 non null characters; "a%%b" is a string with 4 non null characters).
Like this:
printf("hello%%");
//-----------^^ inside printf, use two percent signs together
You can use %%:
printf("100%%");
The result is:
100%
You are using the incorrect format specifier. You should use %% for printing %. Your code should be:
printf("hello%%");
Read more all format specifiers used in C.
The backslash in C is used to escape characters in strings. Strings would not recognize % as a special character, and therefore no escape would be necessary. printf is another matter: use %% to print one %.
You can simply use % twice, that is "%%"
Example:
printf("You gave me 12.3 %% of profit");
Yup, use printf("hello%%"); and it's done.
The double '%' works also in ".Format(…).
Example (with iDrawApertureMask == 87, fCornerRadMask == 0.05):
csCurrentLine.Format("\%ADD%2d%C,%6.4f*\%",iDrawApertureMask,fCornerRadMask) ;
gives the desired and expected value of (string contents in) csCurrentLine;
"%ADD87C, 0.0500*%"