Forgotten Headers and Strange Warnings
In an example program I wrote for a recent instalment of Quality Matters, I had one of those oh-oh moments where you find yourself suddenly abandoned by the wisdom and experience of decades of programming. As usual the explanation was blindingly obvious after the fact, but it was harder than you might expect to get there, in part because GCC is ever so helpful, and C is often not helpful enough.Here's the program:
/* fprintf.fail.test.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if(2 != argc)
{
fprintf(stderr, "supply file name\n");
return EXIT_FAILURE;
}
else
{
FILE* f = fopen(argv[1], "a+");
if(NULL == f)
{
<strong>fprintf(stderr, "could not open %s: %s\n", argv[1], strerror(errno));</strong>
return EXIT_FAILURE;
}
else
{
int n = fprintf(f, "hello, world\n");
if(13 != n)
{
if(n < 0)
{
<strong>fprintf(stderr, "fprintf() failed: %s\n", strerror(errno));</strong>
}
else
{
<strong>fprintf(stderr, "wrote only %d/13 bytes: %s\n", n, strerror(errno));</strong>
}
return EXIT_FAILURE;
}
}
fclose(f);
}
return EXIT_SUCCESS;
}
And here're GCC's compilation warnings:
fprintf.fail.test.c: In function 'main': fprintf.fail.test.c:17: warning: format '%s' expects type 'char *', but argument 4 has type 'int' fprintf.fail.test.c:27: warning: format '%s' expects type 'char *', but argument 3 has type 'int' fprintf.fail.test.c:31: warning: format '%s' expects type 'char *', but argument 4 has type 'int'
Have you picked it, or is it as confusing as I found it the first time I looked at it?
Clearly it thinks that strerror() is of type int.
The answer is that we're missing the string.h inclusion, and so the declaration of strerror() is not seen. This being C, any such missing declaration is assumed to be of type int. This being GCC - as opposed to some other compilers whose libraries less rigorously separate symbols into appearing only where they should appear - you're not going to see the declaration of strerror() unless you include string.h; that's a good thing for many reasons. Perhaps it's because I don't spend the majority of my programming time in C or using GCC, that I was so easily tripped up.
Conclusion:
- Use different compilers, regularly and frequently, to keep your code clean and fresh
- Use different languages, regularly and frequently, to keep your brain clean and fresh

