Here's my code:
int main(){
printf("Hi");
int i=10;
printf("Hi %d",i);
return 0;
}
Now as C can implicitly declare a function this program will compile correctly (As it does with gcc).
But my question is, wasn't the 1st printf declared to return an int with 1 parameter of type char * ?
That makes the 2nd printf an error.
Yet the program compiles with no errors, just warnings (gcc). Why ?
Strictly speaking, implicit declaration is standard violation. It is removed from the standard.
Quoting C11, Foreword
Major changes in the second edition included:
— remove implicit function declaration
That said, in earlier version of C, for a function which is considered declared implicitly (i.e., used before the compiler has knowledge about the function prototype) was supposed to
return an int
accepts any number and type of parameter.
So, as long as the function declaration and the definition does not collide (say, return type mismatch), you'll not get any error. However, a strictly conforming compiler MUST produce a diagnostic.
In your case printf is implicitly defined to be int printf(...), not int printf(char *), thus compiler detects no errors when you call it with different arguments.
Your code is not portable C since you're missing the requisite #include which brings in the function prototype for printf: any sort of implicit declaration was removed in C99.
If you want to write non-portable C, then the best thing you can do is to consult your compiler documentation. In this instance it looks like your friendly compiler is defaulting to int printf(...).
gcc unfortunately has some built in notion of printf even though a header file has not been used.
unsigned int fun ( unsigned int x )
{
printf("%s\n");
printf("%u\n",x);
more_fun("%s\n");
more_fun("%u\n",x);
return(x+1);
}
so.c: In function ‘fun’:
so.c:5:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
printf("%s\n");
^
so.c:5:5: warning: incompatible implicit declaration of built-in function ‘printf’
so.c:5:5: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
so.c:5:12: warning: format ‘%s’ expects a matching ‘char *’ argument [-Wformat=]
printf("%s\n");
^
so.c:7:5: warning: implicit declaration of function ‘more_fun’ [-Wimplicit-function-declaration]
more_fun("%s\n");
^
fortunately if we make our own it does forget at least a little.
void printf(char *, unsigned int );
void more_fun(char *, unsigned int );
unsigned int fun ( unsigned int x )
{
printf("%s\n");
printf("%u\n",x);
more_fun("%s\n");
more_fun("%u\n",x);
return(x+1);
}
so.c:3:6: warning: conflicting types for built-in function ‘printf’
void printf(char *, unsigned int );
^
so.c: In function ‘fun’:
so.c:7:5: error: too few arguments to function ‘printf’
printf("%s\n");
^
so.c:3:6: note: declared here
void printf(char *, unsigned int );
^
so.c:9:5: error: too few arguments to function ‘more_fun’
more_fun("%s\n");
^
so.c:4:6: note: declared here
void more_fun(char *, unsigned int );
^
but we are talking about one compiler, one compiler does not cover it you have to try many/all. Standard or not a compiler could still notice your changing the use of the function and let you know about it, this compiler chooses not to. The error here is not that the compiler didnt notice the function being used differently from one undeclared instance to another but that there was no declaration, and then it does notice the difference as one would hope.
Related
#include<stdio.h>
int main()
{
//void foo();
int c= 5;
c=foo();
printf("\n%d",c);
return 0;
}
void foo()
{
printf("I am foo");
}
When I am commenting the prototype declaration then it gives the output:
I am foo
8
With prototype it gives the error saying:
void value not ignored as it ought ought to be.
My question is, what is internally happening which result into the output when there is no prototype declaration? What is the reason behind it?
I am using Dev C++ editor with TDM-GCC 4.9.2 64bit compiler.
The sole reason this is built successfully is the implicit int rule (now removed in the latest revision of the C standard).
The compiler sees no forward declaration of foo, so it assumes that its return type is int. It then proceeds to build and call your void foo(). After all is said and done, the behavior of your program is undefined.
Gcc compiler give warning and successfully run and return number of character with whitespace but some compiler give an error.
pp.c:10:6: warning: conflicting types for ‘foo’ [enabled by default]
void foo()
^
pp.c:6:6: note: previous implicit declaration of ‘foo’ was here
c=foo();
when there is no prototype declaration
Well, that is invalid C.
To elaborate,
Point 1: You cannot have a function called which is not declared earlier. It is against the C standard rule.Note
Point 2: As soon as you add the forward declaration, you'll be getting compilation error, as a void type cannot be the RHS operand of an assignment operator and this is a constraint violation for assignment operator.
Note:
Pre C99, it was allowed to have a function being called without the prototype known, it was assumed that the function will be returning an int and will be accepting any number of parameters. However, this is precisely forbidden as per C99 and later, as the "implicit int rule" is removed from the standard. (Refer Foreword, paragraph 5, _"remove implicit int"_ in C99 standard).
In your case, for legacy reasons, the compiler still supports the implicit int rule, so it compiles fine, however, the assumption by compiler and the actual function definition is a mismatch. This invokes undefined behavior.
Quoting C11, chapter §6.5.2.2, Function calls
If the function is defined with a type that is not compatible with the type (of the
expression) pointed to by the expression that denotes the called function, the behavior is
undefined.
I am trying to pass an entire array into a my function, but I am getting currently getting the error:
test.c: In function 'main':
test.c:4:18: error: expected expression before ']' token
method(myArray[]);
^
test.c: At top level:
test.c:8:6: warning: conflicting types for 'method' [enabled by default]
void method(int arr[]){
^
test.c:4:3: note: previous implicit declaration of 'method' was here
method(myArray[]);
^
test.c: In function 'method':
test.c:9:3: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
printf("DATA: %d",arr[2]);
^
This is my code (a simplified version of what I'm trying to do that throws up the same error:
int main(){
int myArray[3];
myArray[2]=12;
method(myArray[]);
}
void method(int arr[]){
printf("DATA: %d",arr[2]);
}
When passing an array to a function, you don't need the [] after it. Just using the name of the array is sufficient.
Also, you need to either define or declare your functions before they're used, and you need to #include <stdio.h> so the compiler knows the definition of printf.
#include <stdio.h>
void method(int arr[]);
int main(){
int myArray[3];
myArray[2]=12;
method(myArray);
}
void method(int arr[]){
printf("DATA: %d",arr[2]);
}
More than one point to be mentioned here,
Firstly, include the required header files which contains the function signature of the library functions you're going to use.
Secondly, either forward declare the function prototype or define the function before usage. Be aware, the ancient implicit declaration rule has been officially dropped from the C standards.
Thirdly, change
method(myArray[]);
to
method(myArray);
as the array name itself gives you the base address of the array, which is basically what you need to pass.
I have this following code that executes successfully but how is it possible when function printit is not having data types of passed variables. And then why in output float value is printed correctly but character value is not. I tried even by typecasting it to char.
main( )
{
float a = 15.5 ;
char ch = 'C' ;
printit ( a, ch ) ;
}
printit ( a, ch )
{
printf ( "\n%f %c", a, ch ) ;
}
Its execution gives the result:
15.500000 ╠
In pre-standard C, that was a permitted, though even then not encouraged, way of writing code. There were no prototypes; in the absence of a type specifier, variables were of type int.
If the types were not int, you might write:
print_it_2(a, b, c)
struct dohickey *c;
double b;
{
printf("%d %p %f\n", a, b, c);
}
Note that the variables are listed in one order and defined in another, and a is still an int because it isn't listed at all. The return type of the function was assumed to be int too. However, especially if the function didn't return a value after all (this was before the return type void was supported), people would omit the return type from the declaration and not return a value from the function.
This is no longer good style. If the compiler doesn't complain about it, it should. I compile code (especially for answers on SO) with the extra options:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror ll3.c -o ll3
The missing prototypes and strict prototypes and old style definition are about expunging the last vestiges of such old, pre-standard code. I don't always (usually) show those three options in my answers, but they're there when I compile the code. It means you'll see functions made static (to avoid missing prototypes) and int main(void) instead of int main() (to avoid strict prototypes), and old style definition would shout about the functions discussed in the question.
The second part of the question is 'why did the float value get printed correctly and the character not'.
One of the ways in which non-prototype functions vary is that automatic promotions apply. Any type smaller than int (so char or short) is promoted to int, and float is promoted to double (simplifying slightly). So, in the call printit(a, ch), the values actually passed are a double and an int. Inside the function, the code thinks that a is an int (for concreteness, a 4 byte int), and ditto for ch. These two 4 byte quantities are copied onto the stack (again, simplifying slightly), and passed to printf(). Now, printf() is a variadic function (takes a variable number of arguments), and the arguments passed as part of the ellipsis ... are automatically promoted too. So inside printf(), it is told there are 8 bytes on the stack containing a double value, and sure enough, the calling code passed 8 bytes (albeit as two 4-byte units), so the double is magically preserved. Then printf() is told that there's an extra int on the stack, but the int was not put there by the calling code, so it reads some other indeterminate value and prints that character.
This sort of mess is what prototypes prevent. That's why you should never code in this style any more (and that has been true for all of this millennium and even for the latter half of the last decade of the previous millennium).
Peter Schneider asks in a comment:
Can you point to the relevant standard which allows or forbids undeclared parameters? If it is indeed forbidden, why does gcc not conform to the standard when asked to?
Taking that code and compiling with GCC 4.8.2 on Mac OS X 10.9.2, I get:
$ gcc -std=c11 -c xyz.c
xyz.c:1:1: warning: return type defaults to ‘int’ [enabled by default]
print_it_2(a, b, c)
^
xyz.c: In function ‘print_it_2’:
xyz.c:1:1: warning: type of ‘a’ defaults to ‘int’ [enabled by default]
xyz.c:5:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
printf("%d %p %f\n", a, b, c);
^
xyz.c:5:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
$
The same warnings are given with -std=c99. However:
$ gcc -std=c89 -c xyz.c
xyz.c: In function ‘print_it_2’:
xyz.c:5:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("%d %p %f\n", a, b, c);
^
$
And by providing #include <stdio.h>, even that would be quelled.
Section 6.9.1 of ISO/IEC 9899:2011 covers function definitions (and it's the same section number in C99). However, both of these rule out the 'implicit int' behaviour that C89 had to permit (because an awful lot of pre-existing code hadn't heard of the rules.
However, even C11 allows for the old style definition (with complete types):
function-definition:
declaration-specifiers declarator declaration-listopt compound-statement
declaration-list:
declaration
declaration-list declaration
The 'declaration-listopt' is the list of types between the function declarator and the compound statement that is the function body.
C11 also says:
§6 If the declarator includes an identifier list, each declaration in the declaration list shall
have at least one declarator, those declarators shall declare only identifiers from the
identifier list, and every identifier in the identifier list shall be declared.
I can't immediately find my copy of 'The Annotated C Standard', a book which contains useful information (the 1989/1990 C standard) on the left hand page and frequently less-than-useful information on the right hand page of each spread. This would allow me to quote the standard, but it is AWOL at the moment.
C89 would have been less stringently worded in this paragraph §6.
As to why gcc doesn't reject the sloppily written old-style code, the answer is still 'backwards compatibility'. There is still old code out there, and it allows it to compile when it can, unless its hands are carefully tied behind its back by the use of -Werror.
#include <stdio.h>
void main()
{
int k = m();
printf("%d", k);
}
void m()
{
printf("hello");
}
Output
hello5
What is the void function returning here?
If there is no printf() then the output is 1.
What is happening here?
A void function does not return anything. Your program invokes undefined behavior because it implicitly defines m to have return type int (in C89, if a function is called before it is declared, it's implicitly assumed to have return type int), but then defines it with return type void.
If you add a forward-declaration for m, the compiler will correctly complain that you're trying to use the return value of a void function, which is not possible.
In both cases (void m with caller expecting int, void main with caller-in-C-library expecting int), this is undefined behavior, and your compiler should have chewed you out, e.g. [GCC 4.8 with -Wall]:
test.c:3:6: warning: return type of ‘main’ is not ‘int’
void main()
^
test.c: In function ‘main’:
test.c:7:5: warning: implicit declaration of function ‘m’
int k = m();
^
test.c: At top level:
test.c:13:6: warning: conflicting types for ‘m’
void m()
^
test.c:7:13: note: previous implicit declaration of ‘m’ was here
int k = m();
^
"Implicit declarations" exist only for backward compatibility with pre-C1989 programs, which are more than 20 years out of date at this point. If you had written this code in a more modern style you would've gotten a hard error:
#include <stdio.h>
extern void m(void);
int main(void)
{
int k = m();
printf("%d", k);
return 0;
}
void m(void)
{
printf("hello");
}
⇒
test.c: In function ‘main’:
test.c:7:13: error: void value not ignored as it ought to be
int k = m();
^
The key addition is the extern void m(void); line. The compiler isn't allowed to look ahead to the definition of m when it checks main for errors, so you need a forward declaration to tell it what m's type really is. You should also know that in C (but not C++), void m() means "m takes an unspecified number of arguments". To declare a function taking no arguments, which is what you wanted, you have to write void m(void).
I believe what is happening on your specific system is that the return value of printf, which your code officially ignores, is being left in the return-value register and thus interpreted as the return value of m, but you cannot rely on anything predictable happening. That is what 'undefined behavior' means.
This is undefined behavior.
The reason the compiler lets you do the assignment is that there is no prototype of m available to it. When this happens, C standard says that the function must return int. Since in this case the actual function return type is void, the behavior is undefined. The value that you get in variable k is entirely arbitrary.
The return value of a function usually stored in the one of the CPU registers, EAX for x86. As C it just a friendly assembler, you can always read the value from the register. And you will get whatever was there. Efficiently, int k = m() tells program to store value of register EAX in the variable k.
You have not declared void m(); before calling it in main.
Some compilers assume the return type of unknown function symbols as int (unknown at the time of compilation of course) . In fact, your compiler has probably issued a compilation warning on this.
If you declare this function before main (where it should be declared), then you will probably get a compilation error.
I'm getting a warning by the gcc compiler and the program aborts if the following code is executed I couldn't get why? Would be great help if someone clarified it.
#include<stdio.h>
#include<stdarg.h>
int f(char c,...);
int main()
{
char c=97,d=98;
f(c,d);
return 0;
}
int f(char c,...)
{
va_list li;
va_start(li,c);
char d=va_arg(li,char);
printf("%c\n",d);
va_end(li);
}
GCC tells me this:
warning: 'char’ is promoted to ‘int’ when passed through ‘...’ [enabled by default]
note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
note: if this code is reached, the program will abort
Arguments to variadic functions undergo default argument promotions; anything smaller than an int (such as char) is first converted to an int (and float is converted to double).
So va_arg(li,char) is never correct; use va_arg(li,int) instead.
Yes, this appears to be a quirk in C standard. However, it looks like this is only to do with va_arg().
You can take a look at various implementations of printf() to see how to overcome this. For example, the one in klibc is pretty easy to read.