in the following code in file func.c:
#include <stdio.h>
int Myfunc1(int i, int z)
{
return i;
}
int main()
{
int ans;
/* casting the function into an 'int (int)' function */
ans = ((int(*)(int))(Myfunc1))(5);
printf("ans: %d\n\n", ans);
return 0;
}
i tried to cast an int(int,int) function into an int(int) function an got the gcc warning and note:
func.c:13:32: warning: function called through a non-compatible type [enabled by default]
func.c:13:32: note: if this code is reached, the program will abort
and when trying to run i get:
Illegal instruction (core dumped)
but if i compile this file with a .cpp ending with the gcc compiler it works OK.
can anyone explain the problem of the compiler in the .c case?
GNU GCC recognises all of the following as C++ files, and will use C++ compilation regardless of whether you invoke it through gcc or g++: .C, .cc, .cpp, .CPP, .c++, .cp, or .cxx
From https://stackoverflow.com/a/1546107/1767861
In that case, gcc compiles it in c++, which seems to accept the cast. Why is that ? See https://stackoverflow.com/a/559671/1767861
The problem is your signature for Myfunc1 and the function pointer you try to cast it to are of incompatible types. Instead, you need to do this:
ans = ((int(*)(int, int))(Myfunc1))(5, 5);
The link Thomas Ruiz posted explains why it is undefined behavior.
In summary:
Annex J.2
The behavior is undefined in the following circumstances:
-- A pointer is used to call a function whose type is not compatible with the pointed-to type (6.3.2.3).
6.3.2.3/8
A pointer to a function of one type may be converted to a pointer to a
function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to call
a function whose type is not compatible with the pointed-to type, the
behavior is undefined.
#include <stdio.h>
int Myfunc1(int i, int z)
{
return i;
}
int main()
{
// define a function pointer and initialize it to NULL
int (*ans)(int, int) = NULL;
// get function pointer from function 'Myfunc1'
ans = Myfunc1(5, 6);
// call function using the pointer
printf("ans: %d\n", (*ans));
return 0;
}
Related
This question already has answers here:
Message "warning: implicit declaration of function"
(10 answers)
Closed 6 years ago.
I have this very simple code written in C. They are in two separate files.
myFunction.c
#include <stdlib.h>
int *extFunc() {
int *a = (int *) calloc( 1, sizeof(int) );
*a = 12;
return a;
}
main.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = (int *) extFunc();
int x = *p; // causes segmentation fault !
printf("%d\n", *p); // causes segmentation fault !
}
I compiled it with this command cc myFunction.c main.c and the output is like below
main.c:6:19: warning: implicit declaration of function 'extFunc' is invalid in C99 [-Wimplicit-function-declaration]
int *p = (int *) extFunc();
^
main.c:6:11: warning: cast to 'int *' from smaller integer type 'int' [-Wint-to-pointer-cast]
int *p = (int *) extFunc();
^
2 warnings generated.
and when I run it, it gives Segmentation fault: 11. What am I doing wrong?
I checked the function when it is in the main.c file and it worked. However, I need them to be separate like above.
In my original code there are struct pointers instead of integer pointers. I explained my problem here with a simplified example.
You haven't provided a prototype for extFunc(). Create a header file with:
int *extFunc(void);
and include it in both source files.
Since the compiler can't see a prototype it assumed int as return type for extFunc() which probably truncates the address returned by calloc() on your system (probably 64bit system).
But there's no implicit int rule since C99. Always include prototypes for functions and pay attention to compiler warnings.
The warnings are very important here. Especially the one saying
cast to 'int *' from smaller integer type 'int'
What is happening is that the compiler makes an implicit declaration of the function. One that doesn't return int * but int. On certain platform (most notably 64-bit systems) those are not the same which means the pointer p in your main function is not correct. Dereferencing it will lead to undefined behavior.
You need to add a declaration of your function for it to work:
int *extFunc(void);
int main(void) { ... }
Also note that I have changed the argument type for both your extFunc and for main. This is because in C when you don't explicitly say that a function takes void as argument then it can take any number of unspecified arguments.
Compiling both files is not enough, you need to create a header:
/* myFunction.h */
int *extFunc();
And then, include it in your main file:
#include <stdio.h>
#include <stdlib.h>
#include "myFunction.h" /* here */
int main()
{
...
}
The main cannot see the declaration of the function extFunc, so it's return type default to int.
As types int and int* are not of the same size, the function returns an invalid pointer, which when dereferenced caused a segmentation fault.
You will need to create a header called myFunction.h, which will contain the declaration of the function:
int* extFunc( void );
Include this header in main and also change the definition of extFunc to take no arguments in myFunction.c.
#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.
Following the question Function pointer in Visual Studio 2012 I've started to wonder about the legality of certain assignments to function pointers in C.
The code below compiles with a warning, like I would expect because the assigned function requires more parameters than the function pointer declaration describes (GCC 4.8):
#include <stdio.h>
int test(int x, int y)
{
printf("%d", x);
printf("%d", y);
return 0;
}
int main()
{
int (*test_ptr)(int);
test_ptr = test;
test_ptr(1);
return 0;
}
Same warning appears if changing the code so that assigned function requires less parameters (GCC 4.8). Again, this is expected.
However, the following code compiles without a single warning, although the assigned function needs 2 parameters instead of 0 (GCC 4.8):
#include <stdio.h>
int test(int x, int y)
{
printf("%d", x);
printf("%d", y);
return 0;
}
int main()
{
int (*test_ptr)();
test_ptr = test;
test_ptr();
return 0;
}
No castings are involved anywhere.
Can anyone explain this compiler behavior?
The following:
int (*test_ptr)();
takes an unspecified number of parameters, not zero parameters.
For the latter, write
int (*test_ptr)(void);
P.S. Calling a two-argument function with zero arguments leads to undefined behaviour.
Converting from function pointer to function pointer is legal. What is illegal is calling a function pointer with a type that is not compatible with the actual pointed function.
C99 6.3.2.3 par. 8:
A pointer to a function of one type may be converted to a pointer to a
function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to call
a function whose type is not compatible with the pointed-to type, the
behavior is undefined
If your compiler warned exactly for undefined behavior, it should warn at test_ptr();. But compilers cannot be expected to warn for all undefined behaviors or to warn only for undefined behaviors.
This static analyzer (that others and I work on) does its best to warn on all undefined behaviors and only for undefined behaviors. A lot of compromises are involved, but in this particular case:
$ cat > fp.c
int test(int x, int y)
{
printf("%d", x);
printf("%d", y);
return 0;
}
int main()
{
int (*test_ptr)();
test_ptr = test;
test_ptr();
return 0;
}
$ frama-c -val fp.c
...
fp.c:13:[value] warning: Function type must match type at call site: assert(function type matches)
Line 13 is test_ptr();.
Consider this program:
int func2(char x, char y)
{
return x+y;
}
int (*fp1)(char);
void main()
{
fp1 = func2; /* func2 has one more argument than fp1 */
}
Is the final assignment C90-compliant?
Keil C51 v9.06 accepts the program without warnings, while gcc complains with
warning: assignment from incompatible pointer type
I would like to know if this a bug in the Keil compiler or in fact a C90 compliant way to deal with this.
UPDATE: According to this answer on C99, the corresponding cast is legal. But if you invoke the function pointer you get undefined behavior. Does this mean that the assignment is also legal?
The real question is WHY are you trying to do this?
As soon as you call fp1 when it pointing to func2, func2 will return garbage because argument 2 is not passed (it'll be some random value on the stack, or in a CPU register).
when you build call for function func2 using function pointer fp1, there will be only one value passed on the stack, But in actual, function2 will refer 2nd value on stack as well. So either program will give segmentation fault and fail. Or if does not fail 2nd argument will have garbage value.
I was going to use dlopen, and dlsym on linux to make these two source files work:
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int *(func)(void);
func=dlsym( dlopen("/home/noah/tmp/libmod.so.1", RTLD_LAZY), "func");
printf("%d\n", *func());
return 0;
}
and:
int func()
{
return 42;
}
but when I compile the first one, it keeps saying:
main.c:9: error: lvalue required as left operand of assignment
edit:
I tried adding a cast, and making it a function pointer, but now it says:
main.c:(.text+0x1f): undefined reference to dlopen'
main.c:(.text+0x2b): undefined reference todlsym'
Your declaration of func is confused:
int *(func)(void);
is equivalent to:
int *func(void);
so you're just giving the compiler a prototype for func without declaring a variable; the error occurs because a function is not a valid lvalue; however, a pointer to a function is a valid lvalue so you want this:
int (*func)(void);
And then your printf should be this:
printf("%d\n", func());
You'll also need to cast the return from dlsym to be strictly conforming to standard C:
func = (int (*)(void))dlsym(dlopen("/home/noah/tmp/libmod.so.1", RTLD_LAZY), "func");
A void* pointer can be silently upgraded to any other pointer type except a pointer to a function; gcc -pedantic, for example, will warn that "ISO C forbids assignment between function pointer and ‘void *’" without the cast. I don't have a copy of the standard handy (but someone around here certainly does) so I can't quote chapter and verse but caf is correct on this point (thanks caf).
And you also want to bookmark cdecl.org.
you can't really do what you are attempting
but it should be int (func*)()
and the printf should be func()
but you can't assign the dlsym with all its parameters as a function pointer
hint.... the function pointer "func" is just a pointer, it has no state, its just a memory address
and you shouldn't provide a function called func..... as you are making a pointer called func. you could make a function "int test_function(){ return 42; }
then in main go func = test_function; just to test using the function pointer
There is no need to *func()
printf("%d\n", func());
will be ok, cause func() will return the int, and you try to get dereference (*) of integer
look at precedence of operators (link)