GCC: why a -Wformat warning for this fprintf? - c

We cleaned up a large number of warnings. In several cases, we replaced %s with %d. Everything seemed OK until we realized that the generated code wouldn't compile - strings had been replaced by numbers.
NOTE: I had the wrong revision checked out when I did the copy&paste. The fprintf string has been edited!
GCC output
fedex_plus/classes.c:2425:3: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat]
lines 2424 and 2425:
fprintf(file, "\n//\t%s_ptr create_TIE();\n\tIDL_Application_instance_ptr create_TIE();\n",
ENTITYget_CORBAname(entity));
function ENTITYget_CORBAname:
const char *
ENTITYget_CORBAname (Entity ent)
{
static char newname [BUFSIZ];
strcpy( newname, ENTITYget_name(ent) );
newname[0] = ToUpper (newname [0]);
return newname;
}

My bet is that no declaration of ENTITYget_CORBAname is available at the fprintf spot. Should this be the case, it defaults to the implicit signature:
int ENTITYget_CORBAname(...);
hence the warning about the result type being an int.
Check your code with -Wimplicit (implied by -Wall), or try to put
const char *ENTITYget_CORBAname (Entity ent);
before the fprintf line and check if the warning disappears. If it does, then you're likely missing a header.

If you want to print a pointer value, use %p, if you want to print the string returned from the function, use %s. Don't use %d in any of this cases. See here.

I assume that ENTITY_GETCorbaName() returns a string, so if you want to print that, use %s. If you want to print it as pointer, use %p.

use %s in your printf to print that string or use %p in your printf to show pointer value you can also use %lld to prints its value

Related

Lack of access specifer & in C does not result in a compile error

In C, when & is absent for an argument in scanf(), no compilation error is produced; instead, the displayed results are wrong (i.e. a semantic error occurs).
Consider the following code:
char str[30];
int a;
printf("Enter the value");
scanf("%s %d", str, a); // This is the statement in question.
printf("You entered %s %d", str, a);
Here I know str is a character array so it will have a base address, and thus will not produce a compilation error. But why does the absence of & for the argument a not result in a compilation error?
Also str gives correct output, but the integer is always producing the value -28770 as the output. Why is this?
scanf has the prototype:
int scanf(const char *fmt, ...);
The ... means that any number of arguments of any type may be specified after fmt. Hence it is the responsibility of the caller, not the compiler, to ensure that the provided arguments match what the function will be expecting.
int scanf(const char *format, ...);
This is the prototype for scanf. First argument is char* and other arguments are variable lengths. So no error will be generated.
As Umamahesh P wrote, you won't get a compilation error, because scanf is a variable-argument function. As to what happens when you run the program, it is what the C standard calls "undefined behaviour". Anything can happen. You need to look at what happens at the machine-instruction and memory address level to see what exactly scanf does with the integer value you gave it instead of a pointer.
You can get a compiler warning, depending on what compiler you use and what options you specify.
Also even if it tries to show those warnings, your compiler will be totally unable to do it if you use vscanf() or if you use a dynamic string as your format parameter.
For instance, this is the output I get using mingw-64 gcc 4.5.4:
gcc -Wall -o small.exe small.c
small.c:7:3: warning: format '%d' expects type 'int *', but argument 3 has type 'int'
small.c:7:8: warning: 'a' is used uninitialized in this function
Just add -Werror option to turn these warnings into errors.

Runtime typechecking for pointers

I want to know how scanf function is implemented. (Just for fun of course) Number of arguments is variable, so it's certainly implemented by va_list, va_arg macros.
It also throws some warnings, when number of arguments does not match with format string. This could be done by parsing format string and comparing it with number of arguments. No magic.
The only thing that I can't see how implemented, is type checking. When type of an argument (pointer to a data) does not match corresponding declaration in format literal, scanf produces a warning. How can one check type of data that a pointer points to?
Example:
#include<stdio.h>
int main()
{
char buffer1[32], buffer2[32];
int n;
double x;
scanf("%s %s %d",buffer1, buffer2, &x); // warning
scanf("%s %s %d",buffer1, buffer2, &n); // ok
}
Output:
warning: format ‘%d’ expects argument of type ‘int *’,
but argument 4 has type ‘double *’ [-Wformat]
AFAIK the C library is not a part of C language/Compiler, so there is nothing language-related in <stdio.h>. I'm assuming the warning is produced by implementation of scanf, not by compiler [?]. (Maybe using #warning)
If I want to do something similar in some code, how do I know which data type a pointer is pointing to?
Note: I have downloaded source code of GNU C library and looked at scanf.c. I can't find my way through the very complicated code. There is a lot of #ifndef s and calls to other functions with strange names and structure...
This check is handled by the gcc compiler, specifically for scanf/printf functions.
It's such a common error that it's worth adding special case code to the compiler for these functions.
see the GCC -WFormat flag here: http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Warning-Options.html
-Wformat : Check calls to printf and scanf, etc., to make sure that the arguments supplied have types appropriate to the format string
specified, and that the conversions specified in the format string
make sense. This includes standard functions, and others specified by
format attributes (see Function Attributes), in the printf, scanf,
strftime and strfmon (an X/Open extension, not in the C standard)
families.
These checks are not implemented by all compilers, so it's certainly not something to rely on.
With GCC you can use Function Attributes 'format' and 'format-arg' to tell the compiler to apply the same checks to your functions.
format (archetype, string-index, first-to-check) The format attribute
specifies that a function takes printf, scanf, strftime or strfmon
style arguments which should be type-checked against a format string.
For example, the declaration:
extern int my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
...causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument
my_format.
The warning is generated by the compiler. You declared x as a double, so it knows &x is a double*. Then it scans the format string and sees that the format requires an int* there, hence it warns.

C printf printing random number

I am very new to C Programming and have a doubt... I've been asked to find errors in certain segments of C code... and this segment has me a bit confused so would appreciate the help...
int main(void)
{
int myInt = 5;
printf("myInt = %d");
return 0;
}
As far as i understand there is nothing wrong in this code. What i wanna know is why is this statement printing out a random number ??
The output i get is
myInt = 1252057154
Would appreciate the help... Thanks
You should read more about C programming.
And you should enable all warnings and debugging when compiling. With GCC, this means gcc -Wall -Wextra -g (on Linux at least).
When compiling with
gcc -Wall -Wextra -g john.c -o john
I am getting the following warnings:
john.c: In function ‘main’:
john.c:4:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
john.c:4:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
john.c:4:5: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat]
john.c:3:9: warning: unused variable ‘myInt’ [-Wunused-variable]
So the correction is simple:
/* file john.c */
#include <stdio.h>
int main(void)
{
int myInt = 5;
printf("myInt = %d\n", myInt);
return 0;
}
which gets compiled without warnings.
Notice the \n at the end of printf format string. It is important.
Always enable all the warnings the compiler can give you and trust the compiler, so correct your code till no warnings is given.
And learn to use the debugger (e.g. gdb on Linux).
The behavior you observed is undefined behavior; anything could happen with a standard conforming implementation of C (even an explosion).
Happy hacking.
printf (and similarly scanf) works like this:
Let's say you issue a call to printf
printf("%d some text %f %u %hu some more text\n", arg1, arg2, arg3, arg4)
printf goes over the format string and replaces %? with an argument, based on ?
%d some text %f %u %hu some more text
| | | |
arg1 arg2 | arg4
arg3
Now the thing with functions taking variable number of arguments is that, they don't know if the arguments exist, that's why they just take data from a specific part of the stack based on the format string. If you write:
printf("%d %f %u\n");
it reads three non existing data from the stack, most probably get the values stored when calling the function (values that should be hidden from you)
Well, if it's printing something wrong, the problem is in the printf call:
printf("myInt = %d");
Which arguments you're expected to pass?
It should be this:
printf("myInt = %d",myInt);
If you don't include the variable, then it basically pulls a random chunk of memory in. In addition, it might cause more wierd stuff to happen if you do this with a larger chunk of code. Always make sure that you have as many variables from a printf statement as you need, or bad stuff will result.
printf is a function that receives one or more arguments.
In your case it received only one argument (which is legal) but the argument containes %d which tells printf to take the second argument instead of the %d.
printf takes the "second argument" from the stack, and because only one argument was pushed to the stack (the string), it uses the return address as the second argument.
int main(void)
{
int myInt = 5;
printf("myInt = %d",myInt);
return 0;
}
The only change in the code is I added myInt variable in the printf statement if you see at the end.Whenever a variable is assigned some value it can be displayed only by passing it to the printf() function with the corresponding type specifier.Its a rule in C.

Why does atoi() cause a bus error?

#include <stdlib.h>
#include <stdio.h>
main()
{
const char* str_int = "777";
const char* str_float = "333.3";
int i = atoi(str_int);
float f = atof(str_float);
printf("%s %s", i, f);
}
I have tried several bits of example code I‛ve found online, and all of them cause bus errors. Why is this happening?
Your printf is incorrect. Try this instead:
printf("%d %f", i, f);
The problem is that your format specifiers are %s, which expect strings. But you gave it an intand a float. Therefore the result is undefined behavior.
The reason why it's crashing is because printf will try to read the parameters as strings (which are pointers) and deference them as such, but they are invalid pointers.
Here's a reference on printf and its format specifiers:
http://www.cplusplus.com/reference/clibrary/cstdio/printf/
Please take the habit of asking warnings from your compiler. With gcc it is the -Wall option and (on Linux/Debian/Sid gcc 4.6) I'm getting with your example file david.c using the gcc -Wall -g -o david david.ccommand:
david.c:4:1: warning: return type defaults to 'int' [-Wreturn-type]
david.c: In function 'main':
david.c:11:5: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat]
david.c:11:5: warning: format '%s' expects argument of type 'char *', but argument 3 has type 'double' [-Wformat]
david.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
A newbie should correct his code till the compiler gives no more warnings. There are very very rare cases when leaving a warning is acceptable (it should happen less than once a year for a seasoned C programmer).
It's not, printf is. You're telling printf that you're passing it two strings ("%s"), when in fact you're passing an int and a float. It should be:
printf("%d %f", i, f);
Otherwise it'll treat the two arguments on the stack as strings (ie. char*).
Since two char*s haven't been passed as promised, when it tries to print the values of what it thinks are two strings on the stack, it'll cause undefined behaviour and potentially crash. This is most likely because the pointers it's trying to dereference are invalid and don't in fact point to a valid address.
printf has no way of telling if the arguments you're passing are correct, your compiler warnings however will. Turn up your compiler warnings.
Read here for more about warning options with gcc (if that's what you're using): http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Read here for more about the format specifiers (ie. %s, %d): http://www.cplusplus.com/reference/clibrary/cstdio/printf/
Printf is not correct.Change it to
printf("%d,%f",i,f);
Refer this link to understand the printf syntax clearly:
http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output

The program compiles but terminates on execution. Why?

int main() {
char first,second,third,fourth,fifth;
scanf("%c %c %c %c %c",first,second,third,fourth,fifth);
printf("%c%c%c%c%c",first,second,third,fourth,fifth);
getch();
return 0;
}
The above program is compile without any error (GNU GCC) but on execution minimizes the 'current window' and terminates again without any error. Why?
Update
int main() {
char first,second,third,fourth,fifth;
scanf("%c %c %c %c %c",&first,&second,&third,&fourth,&fifth);
printf("%c%c%c%c%c",first,second,third,fourth,fifth);
getch();
return 0;
}
The above code is the changed after the answers received, but still behaves the same way, just that the compiler does throw any error or even warnings this time.
Because you're passing uninitialized values into scanf as pointers. Try
scanf("%c %c %c %c %c", &first, &second, &third, &fourth, &fifth);
Quick Solution.
Because you are passing char-variables to scanf instead of pointers.
scanf("%c %c %c %c %c", &first, &second, &third, &fourth, &fifth);
Rule of Thumb.
icemanind mentioned that "When using scanf, you must preface each variable with an Ampersand", but that is too broad. If you stricly follow that rule, you might be passing pointers-to-pointers-... . Instead, as rule of thumb, you must
Pass the address of the variable you want to write into.
and
The type of the target must match exactly the specification of the format tokens,
About the latter: E.g., you are screwed if you pass a double-pointer for the %d format token.
Prevention.
If you had used compiler warnings, in your specific case -Wformat, but in the general case just use -Wall (and preferably -Wextra, too), the compiler would have warned you:
gcc -Wall -Wextra foo.c
warning.cc: In function `int main()':
warning.cc:4: warning: format argument is not a pointer (arg 2)
warning.cc:4: warning: format argument is not a pointer (arg 3)
warning.cc:4: warning: format argument is not a pointer (arg 4)
warning.cc:4: warning: format argument is not a pointer (arg 5)
warning.cc:4: warning: format argument is not a pointer (arg 6)
For the curious: This warning is based on a compiler extension that targets format strings (see gcc's list of attributes:
The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments which should be type-checked against a format string. For example, the declaration:
extern int
my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
When using scanf, you must preface each variable with an Ampersand symbol because you must pass in a pointer to a non-pointer variable, not just a variable itself, like so:
scanf("%c %c %c %c %c",&first,&second,&third,&fourth,&fifth);

Resources