What causes an "incompatible implicit declaration" warning? - c

I am trying find out the number of characters in a string using the strlen() function. The user inputs a sentence and the code must display the number of characters in the string.
int l;
char string[64];
printf("Enter a statement: \n");
scanf("%s",&string);
l = strlen(string);
printf("%d",l);
The code runs incorrectly with the following warning :
[Warning] incompatible implicit declaration of built-in function 'strlen'
I did find the correct code online, but what exactly is wrong with my logic ? A little help required.

Observation, firstly
The code runs incorrectly with the following warning : [Warning]
incompatible implicit declaration of built-in function 'strlen'
This is because you didn't include the necessary header for strlen.
#include <string.h>
Secondly, here:
scanf("%s",&string);
string is character array and array name itself address, hence while scanning & is not required.
scanf("%s", string); /* remove & */
Also, always check the return value of functions like scanf. Check the manual page of scanf() to know what it returns. For example:
int ret = scanf("%s", string);
if (ret == 1) {
/* success, proceed further */
}
else {
/* proper error handling */
}

The reason for the warning is forgetting to include string.h
What the warning means in detail, is that in older C from the 90s, it was valid to use a function without declaring it. So if you didn't provide the relevant header like string.h where the declaration is found, the compiler would then "guess" what function format you want and try to silently declare the function "between the lines".
The compiler would have implicitly given you this:
int strlen (); // accepts any parameters
But the real and correct strlen declaration is this:
size_t strlen (const char *s);
These aren't compatible types, hence the warning about incompatible declaration. The actual definition of the strlen function matches the latter, but not the former, so this is a bug.
From the year 1999 and beyond, implicit function declarations were removed from the C language, since they were plain dangerous. The gcc compiler still allows obsolete style C though, if you configure it a certain way.
If you are a beginner, you should always compile with a strict and standard compliant setup:
gcc -std=c11 -pedantic-errors -Wall -Wextra
This will swap the mentioned warning for an error, which is nice since this was a program-breaking bug.

Related

strlen function still work without including header file

I'm new to C, just a question on strlen. I know that it is defined in <string.h>. But if I don't include <string.h> as:
#include <stdio.h>
int main()
{
char greeting[6] = { 'z', 'e', 'l', 'l', 'o', '\0' };
printf("message size: %d\n", strlen(greeting));
return 0;
}
it still works and prints 5, I did receive a warning which says warning: incompatible implicit declaration of built-in function ‘strlen’ but how come it still compile? and who provides strlen()?
There are several things going on here.
As of the 1990 version of C, it was legal to call a function without a visible declaration. Your call strlen(greeting) would cause the compiler to assume that it's declared as
int strlen(char*);
Since the return type is actually size_t and not int, the call has undefined behavior. Since strlen is a standard library function, the compiler knows how it should be declared and warns you that the implicit warning created by the call doesn't match.
As of the 1999 version of the language, a call to a function with no visible declaration is invalid (the "implicit int" rule was dropped). The language requires a diagnostic -- if you've told the compiler to conform to C99 or later. Many C compilers are more lax by default, and will let you get away with some invalid constructs.
If you compiled with options to conform to the current standard, you would most likely get a more meaningful diagnostic -- even a fatal error if that's what you want (which is a good idea). If you're using gcc or something reasonable compatible with it, try
gcc -std=c11 -pedantic-errors ...
Of course the best solution is to add the required #include <string.h> -- and be aware that you can't always rely on your C compiler to tell you everything that's wrong with your code.
Some more problems with your code:
int main() should be int main(void) though this is unlikely to be a real problem.
Since strlen returns a result of type size_t, use %zu, not %d, to print it. (The %zu format was introduced in C99. In the unlikely event that you're using an implementation that doesn't support it, you can cast the result to a known type.)
The C standard library is linked automatically. That's what gives you access to the strlen function.
Including the header file helps the compiler out by telling it what kind of function strlen is. That is, it tells it what kind of value it returns and what kind of parameters it takes.
That's why your compiler is warning you. It's saying, "You're calling this function but I haven't been told what kind of function it is." Often a compiler will make a guess. You're passing in a char[] so the compiler figures the function must take a char* as an argument. As for the return type, the compiler makes the guess that the return value is an int.

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.

%s expects 'char *', but argument is 'char[100]'

I have something along the lines of:
#include <stdio.h>
typedef struct {
char s[100];
} literal;
literal foo()
{
return (literal) {"foo"};
}
int main(int argc, char **argv) {
printf("%s", foo().s);
return 0;
}
And I get this error when compiling it (with gcc):
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘char[100]’ [-Wformat=]
any1 has any ideas on how I can fix it? And what is wrong with that function return type?
EDIT
The problem (if not clear in the discussion) was the c standard gcc was using to compile the file. if you use -std=c99 or -std=c11 it works.
It is not an error but a warning, not all warnings that -Wall produces are sensible.
Here the compiler is "kind-of" right: before evaluation your argument is an array and not a pointer, and taking the address of a temporary object is a bit dangerous. I managed to get rid of the warning by using the pointer explicitly
printf("%s\n", &foo().s[0]);
Also you should notice that you are using a rare animal, namely an object of temporary lifetime, the return value or your function. Only since C99, there is a special rule that allows to take the address of such a beast, but this is a corner case of the C language, and you would probably be better off by using some simpler construct. The lifetime of the pointer ends with the end of the expression. So if you would try to assign the pointer to a variable, say, and use it later on in another expression, you would have undefined behavior.
Edit(s): As remarked by mafso in a comment, with C versions from before C99, it was not allowed to take the address of the return value of the function. As Pascal Cuoq notes, the behavior of your code is undefined even for C99, because between the evaluation of the arguments and the actual call of the function there is a sequence point. C11 rectified this by indroducing the object of temporary lifetime that I mentioned above.
I don't exactly why maybe someone with more knowledge in C than me can explain it but writing main() on this way:
int main(int argc, char **argv) {
literal b = foo();
printf("%s", b.s);
return 0;
}
The code prints "foo" correctly on GCC 4.5.4

What does "char *p, *getenv();" do? Why a function with no args in a variable declaration line?

I'm reading a bit of code in C, and in the variable declaration line, there's "char *p, *getenv();"
I understand "char *p" of course. What does "char *getenv()" do? Later on in the code, the function getenv() is called with a variable passed to it. But what's the point of "char *getenv();" without any arguments?
Sorry if this is basic. I'm just starting to learn C.
It is "valid C" (I would almost say "unfortunately") - but it is not particularly useful. It is a "declaration without declaration" - "I will be using a function getenv() but I'm not going to tell you what the arguments will be". It does have the advantage of preventing a compiler warning / error - something that would normally be prevented with a "real" function prototype, for example by including the appropriate .h file (in this case, stdlib.h).
To clarify: the following code
#include <stdio.h>
int main(void) {
char *p;
p = getenv("PATH");
printf("the path is %s\n", p);
return 0;
}
will throw a compiler warning (and you should never ignore compiler warnings):
nonsense.c: In function ‘main’:
nonsense.c:5: warning: implicit declaration of function ‘getenv’
nonsense.c:5: warning: assignment makes pointer from integer without a cast
Either adding #include <stdlib.h> or the line you had above, will make the warning go away (even with -Wall -pedantic compiler flags). The compiler will know what to do with the return value - and it figures out the type of the arguments on the fly because it knows the type when it sees it.
And that is the key point: until you tell the compiler the type of the return value of the function it does not know what to do (it will assume int, and make appropriate conversions for the variable you are assigning to - this can be inappropriate. For example, a pointer is often bigger than an int, so information will be lost in the conversion.)
It's a declaration (an old-style one without a prototype, since the argument list is missing) for the function getenv. Aside from being arguably bad style to hide a function declaration alongside the declaration of an object like this, it's bad to omit the prototype and bad not to be using the standard headers (stdlib.h in this case) to get the declarations of standard functions.

Extremely simple C program won't compile in gcc compiler

I have the following program
main()
{
char a,b;
printf("will i get the job:");
scanf("%c",&a);
printf("%c",a);
printf("We did it");
}
I saved the file as Hope.c. When I try to compile the code above with the gcc compiler, I will get the following error:
Hope.c:In function 'main':
Hope.c:4:2:warning:incompatible implicit declaration of built-in function 'printf' [enabled by default]
Hope.c:5:2:warning:incompatible implicit declaration of built-in function scanf[enabled by default]
The compiler gives this error when I use printf() or scanf(), even in a simple "Hello world" program.
Is there something wrong with my code, or is there a problem with the compiler?
You're missing #include <stdio.h> at the top. Note that these were warnings, though, not errors. Your program should still have compiled as is.
Also, for good measure, you should write out the return type and parameters to main() and return a value at the end.
#include <stdio.h>
int main(void)
{
char a,b;
printf("will i get the job:");
scanf("%c",&a);
printf("%c",a);
printf("We did it");
return 0;
}
When you call functions that you're not familiar with, look at the man page and include the headers that are mentioned there. It's #include <stdio.h> in your case.
That's really extermely important, e.g. I have experienced printf( "%s", func( ) ) causing a segmentation fault although func() returned a valid null terminated string, but there was no prototype that declared the return type of func() as char * (doing a little bit research, we found that only the last four bytes of the 64 bit pointer have been passed to printf())
Yes, there's something wrong with the code. You're using the functions printf and scanf without declaring them.
The usual thing to do is use the declarations shipped with the compiler (because they're known to be correct) with
#include <stdio.h>
C.89/C.90 permits implicit declarations of functions. Your warning messages are informing you that you have not provided explicit declarations for scanf and printf. As has been mentioned, you can correct this by adding #include <stdio.h> to the beginning of your program. By not doing so, the behavior of your program is undefined.
Because scanf() and printf() have implicit declarations, they are treated as if their prototypes were given as:
extern int scanf ();
extern int printf ();
These declarations state that scanf() and printf() take an as of yet unknown number of arguments and return and int. However, this kind of declaration still assumes that these functions will take a fixed number of arguments. This is incompatible with their true prototypes, in which they take a variable number of arguments:
extern int scanf (const char *, ...);
extern int printf (const char *, ...);
Your C compiler apparently knows about the true prototypes of these functions because it treats those functions as "built-ins", meaning it can generate special case code when compiling to source code that calls those functions. Since the implicit declaration does not match its built-in knowledge of their prototypes, it generated the warning.
A compiler that did not have this "built-in knowledge" probably would not have generated the warning. It would then have generated code to call scanf() and printf() as if they took a fixed number of arguments. The error then may occur at runtime, since the calling convention for a function that takes a variable number of arguments may differ from the calling convention of a function that takes a fixed number of arguments.
This is all described in C.89 §3.3.2.2.
If the expression that precedes the parenthesized argument list in
a function call consists solely of an identifier, and if no
declaration is visible for this identifier, the identifier is
implicitly declared exactly as if, in the innermost block containing
the function call, the declaration
extern int identifier();
appeared.
...
If the expression that denotes the called function has a type that
does not include a prototype, the integral promotions are performed on
each argument and arguments that have type float are promoted to
double. ... If the function is defined with
a type that includes a prototype, and the types of the arguments after
promotion are not compatible with the types of the parameters, or if
the prototype ends with an ellipsis ( ", ..." ), the behavior is
undefined.
Note that C.99 removes the allowance for implicit function declarations.

Resources