I am doing a C exercise that involves loading a shared library dynamically. When I compile my test program using gcc -o test2 test2.c -ldl command, I get an error:
test2.c: In function ‘main’:
test2.c:27:5: error: too many arguments to function ‘test’
(*test)(array, size);
This is the bit where I get the error:
void (*test)(void);
test = dlsym(handle, "lib_fill_random");
(*test)(array, size);
lib_fill_random is declared with two arguments in both in .h and .c files as void lib_fill_random(double *array, int size);, and it works perfectly fine by itself.
What could be causing this issue?
The function pointer declaration has to match the declaration of the actual function. So it should be:
void (*test)(double *, int);
Your declaration states that the function takes no arguments, so you get an error when you call it with arguments.
Related
I have some example code. When I uncomment the invalid_call function call I get a compiler error as expected. Unfortunately, calling my_function with wrong number of arguments still compiles leading to undefined behavior (UB).
main.c
#include <linux/module.h>
#include <linux/kernel.h>
#include "header.h"
extern void my_function(int x);
static int my_init(void)
{
my_function(5);
// invalid_call( 5 ); // doesn't compile
return 0;
}
static void my_exit(void)
{
pr_info("removing module");
}
module_init(my_init);
module_exit(my_exit);
func_source.c
#include <linux/kernel.h>
void my_function(int x, int y)
{
pr_info("%d %d",x,y);
}
header.h
void invalid_call(int x, int y)
{
return;
}
Expected output:
Compiler error when calling my_function() with only one argument.
Actual output:
Code compiles and prints a random value for y, essentially UB.
I know that extern void my_function(int x); is just another declaration so I don't think compiler needs to throw an error however, when I call my_function with a single argument, it shouldn't be able to find a match to any function definition. Unfortunately, instead of a compiler error I run into UB.
How does this work? I know UB is UB but how why does it become UB. I thought the function signature mismatch would cause a compiler. My suspicion is the extern declaration but still...
Also, bonus question. How do I avoid running into this problem again? Any design patterns or practices I can follow?
Here is the Makefile if you want to test it out yourself.
obj-m += main.o
example-y := ./src/main.o ./src/func_src.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Folder structure:
./Makefile
./src/main.c
./src/my_func.c
Thanks in advance.
In C, at least, neither the compiler nor the linker has global knowledge of all the functions in all the source files of your program (or kernel module, or whatever). The compiler compiles one source file at a time, and all it has to go on is the declarations -- including the prototypes -- that are visible during that one compilation. So if the prototype is wrong -- you're doomed. The compiler validates your (incorrect) call against the (incorrect) prototype, and finds no mismatch, and so generates an (incorrect) call that passes one argument, leading to the behavior you see.
For this reason it's an excellent idea to:
never put external prototypes in .c files, but rather, in .h files, which you include wherever you call the functions, and
also include the .h file in the source file where you define the function.
That way, not only does the compiler check that the calls match the prototype, it can also check that the prototype matches the actual definition, and since there's only one copy of the prototype (in that one .h file), it's more or less impossible for it to fall out of sync and end up being incorrect. See also this question.
In your question, you seemed to think that it wouldn't even be possible for the incorrect call to be linked up with the two-argument-accepting definition. That might be true in C++, where "name mangling" arranges for a function's arguments to be part of its signature. But nothing like that happens in C. Your function's sole identity -- in the symbol table, and as far as the linker is concerned -- is the name my_function, and nothing at link time prevents a one-arg-passing call from being matched up with the two-arg-accepting definition.
Some ways to detect this problem:
building in gcc with link-time optimization will usually flag this.
Using -Wmissing-prototypes would have warned for func_source.c that you have an externally-visible function with no prototype.
You should have the correct prototype in a header file that is included by all units that want to call the function, as well as the unit containing the function definition. The latter warning flag will detect if you forget to put the prototype in the unit containing the definition (which would have caused a compilation error due to the prototype not matching the definition).
the OPs posted code results in the following messages from the compiler:
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘invalid_call’:
untitled.c:1:23: warning: unused parameter ‘x’ [-Wunused-parameter]
void invalid_call(int x, int y)
^
untitled.c:1:30: warning: unused parameter ‘y’ [-Wunused-parameter]
void invalid_call(int x, int y)
^
untitled.c: In function ‘my_init’:
untitled.c:15:5: warning: implicit declaration of function ‘my_function’; did you mean ‘myFunction’? [-Wimplicit-function-declaration]
my_function(5);
^~~~~~~~~~~
myFunction
untitled.c: In function ‘my_exit’:
untitled.c:22:5: warning: implicit declaration of function ‘pr_info’ [-Wimplicit-function-declaration]
pr_info("removing module");
^~~~~~~
untitled.c: At top level:
untitled.c:25:1: warning: data definition has no type or storage class
module_init(my_init);
^~~~~~~~~~~
untitled.c:25:1: warning: type defaults to ‘int’ in declaration of ‘module_init’ [-Wimplicit-int]
untitled.c:25:1: warning: parameter names (without types) in function declaration
untitled.c:26:1: warning: data definition has no type or storage class
module_exit(my_exit);
^~~~~~~~~~~
untitled.c:26:1: warning: type defaults to ‘int’ in declaration of ‘module_exit’ [-Wimplicit-int]
untitled.c:26:1: warning: parameter names (without types) in function declaration
untitled.c:28:6: warning: conflicting types for ‘my_function’
void my_function(int x, int y)
^~~~~~~~~~~
untitled.c:15:5: note: previous implicit declaration of ‘my_function’ was here
my_function(5);
^~~~~~~~~~~
untitled.c:20:13: warning: ‘my_exit’ defined but not used [-Wunused-function]
static void my_exit(void)
^~~~~~~
untitled.c:13:12: warning: ‘my_init’ defined but not used [-Wunused-function]
static int my_init(void)
^~~~~~~
Compilation finished successfully.
Suggest enabling the warnings when compiling, then fix those warnings
I have simple programm in two units:
count_words.c:
int main( int argc, char ** argv )
{
printf("starting\n");
int i = aaa(55555);
printf("%d",i);
printf("ending\n");
return i;
}
clean.c:
int aaa()
{
printf("aaa\n");
return 5;
}
Makefile:
count_words: clean.o count_words.o -lfl
gcc count_words.o clean.o -lfl -ocount_words
%.o:%.c
gcc -c -o $# $<
I'm wondering why this code compiles and runs without problem. Function aaa() in clean.c has no parameters, but in count_words.c I pass 55555. Why it compiles and runs. Can I expect unexpected errors in such situations?
UPD:
I have changed int aaa() to int aaa(void), but still have warning and not error.
As you noticed I didn't include header of clean.c in count_words.c and it compiles anyway. Why then I must include headers at all?
The program has undefined behaviour.
According to the C Standard (6.5.2.2 Function calls)
..If the number of arguments does not equal the number of parameters, the behavior is undefined.
The function is defined as having no parameters but is called with one argument.
From the C Standard (6.7.6.3 Function declarators (including prototypes))
14....An empty list in a function declarator that is part of a definition of
that function specifies that the function has no parameters.
In C++ this code will not compile.
I'm trying to compile third party source code using gcc 4.8 on Ubuntu Linux (12.04 x64) with a lot of utilities and test applications where executable entry point is not called main. Don't ask me why - I don't know the answer.
Linker of course complains:
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Is it possible to force linker to use another method as the entry point? I tried to use these linker options with gcc but neither of them worked:
-Wl,-eWhatever or -Wl,--entry=Whatever or -Wl,-e,Whatever. All ended with the same error.
As by C Standard, the hosted environment (that I guess is your case as/if you want to use standard library headers*) forces you to keep with main function. From C11 §5.1.2.2.1/p1 (emphasis mine):
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as
argc and argv, though any names may be used, as they are local to the
function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other
implementation-defined manner.
There are two options that I can think of to bypass main function requirement in your situation:
Create separate object file (that is, by gcc -c) with main symbol, that just (declares and) calls (i.e. wraps) your custom entry point (possibly passing through argc and argv invocation arguments). This would make linker happy and is as simple as adding single makefile rule.
Compile your program as gcc -DWhatever=main. This essentially replaces every instance of Whatever preprocessing token by main, so linker thinks of Whatever as "proper" main function.
* some headers must be available in freestanding environment too, such as <stddef.h> and <float.h>, see §4/p6 for full list of them.
Here is some basic ilustration of both options. Each assumes, that foo.c is as following:
foo.c
#include <stdio.h>
void foo(void)
{
printf("foo\n");
}
First method:
main.c
/* declare an entry point */
void foo(void);
/* define main as wrapper function */
int main(void)
{
foo();
return 0;
}
Compile & run:
$ gcc -c main.c
$ gcc foo.c main.o
$ ./a.out
foo
Second method:
$ gcc -Dfoo=main foo.c
$ ./a.out
foo
Some things may require more tweaking, but I hope you catch the idea.
I'm developing a small library for a PID controller using avr-gcc.In spite of declaring the function in the header file and defining it separately in a .c file the compiler is throwing the following errors:
Compiling C: pid.c
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -funsigned-char -
funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-
adhlns=./pid.lst -std=gnu99 -MMD -MP -MF .dep/pid.o.d pid.c -o pid.o
pid.c:5: error: expected declaration specifiers or '...' before '(' token
pid.c:5: warning: function declaration isn't a prototype
pid.c:5: error: 'type name' declared as function returning a function
pid.c:5: error: conflicting types for 'PID_init'
pid.h:23: error: previous declaration of 'PID_init' was here
pid.c: In function 'PID_init':
pid.c:5: error: parameter name omitted
The header file contents of pid.h are as follows:
#include<avr/io.h>
#include<util/delay.h>
#ifndef PID_CONTROLLER
#define PID_CONTROLLER
struct PIDCONTROL
{
float error;
float prev_error;
float Kp;
float Ki;
float Kd;
float pid;
float P;
float I;
float D;
float setpoint;
};
void PID_init(float,float,float,float,struct PIDCONTROL*);
float PID(float,struct PIDCONTROL*);
#endif
The definitions for the declared functions have been made in pid.c which contains the code shown below:
#include<avr/io.h>
#include<util/delay.h>
#include "pid.h"
void PID_init(float SP,float Kp,float Ki,float Kd,struct PIDCONTROL *a)
{
a->Kp=Kp;
a->Ki=Ki;
a->Kd=Kd;
a->pid=0;
a->setpoint=SP;
a->prev_error=0;
}
float PID(float PV,struct PIDCONTROL *a)
{
a->error=(a->setpoint)-PV;
a->P=(a->Kp)*(a->error);
(a->I)+=(a->Ki)*(a->error)*1.024;
a->D=(a->Kd)*((a->error)-(a->prev_error))/1.024;
a->pid=(a->P)+(a->I)+(a->D);
a->prev_error=a->error;
return(a->pid);
}
I couldn't just figure out what's wrong with the code. Any help is appreciated.Thanks in advance.
The avr/io.h file also brings in avr/common.h which contains this little snippet:
/*
Stack pointer register.
AVR architecture 1 has no RAM, thus no stack pointer.
All other architectures do have a stack pointer. Some devices have only
less than 256 bytes of possible RAM locations (128 Bytes of SRAM
and no option for external RAM), thus SPH is officially "reserved"
for them.
*/
# ifndef SP
# define SP _SFR_MEM16(0x3D)
# endif
(it's actually a bit more complicated than that, with multiple paths depending on your architecture, but that cut down example shows what the actual problem is, at least).
It's actually defining a pre-processor macro for SP which means, when you attempt to use that in your code with a function definition along the lines of:
void PID_init(float SP,float Kp,float Ki,float Kd,struct PIDCONTROL *a)
what you'll actually get is something like:
void PID_init(float _SFR_MEM16(0x3D),float Kp,float Ki,float Kd,struct PIDCONTROL *a)
which will cause the compiler phase to complain bitterly.
I'm actually a big believer in reasonably self-describing variable names so would generally choose something more verbose than SP but you'll probably find that, even if you make it mySP, it'll fix the immediate problem.
I have these two different program where I want to access the static variable declared in program1 from program2.
Program1. (
/* file a.c */)
#include<stdio.h>
static int a = 100; /* global static variable not visible outside this file.*/
int *b = &a; /* global int pointer, pointing to global static*/
Program2
#include<stdio.h>
/* file b.c */
extern int *b; /* only declaration, b is defined in other file.*/
int main()
{
printf("%d\n",*b); /* dereferencing b will give the value of variable a in file a.c */
return 0;
}
While I compile program1 , gcc a.c , no compilation error, but while I compile program2 ( gcc b.c) I am getting compilation error .
test_b.c:(.text+0x7): undefined reference to `b'
collect2: error: ld returned 1 exit status
Why there is compile error ? Here is the link of program static
Thanks in advance.
EDIT 1:
My intention to use static variable from other program. I thought every .c program must have main() function and only .h program have declaration , I am wrong at that point. So I remove main() function from a.c program and instead of compiling two different program separately , now I compile only once using gcc a.c b.c as per suggestion of Filip. Now it's working fine. Thanks all of you.
You have to link against a.c while compiling b.c:
gcc a.c b.c
You can't expect the linker to magically find the C file where b is defined. extern means it is defined elsewhere - you have to say where. By compiling and linking with a.c, the linker can now find a declaration for b.
Of course, you can't have 2 main() functions.
Well, your code already said it. b.cpp only has a declaration, not a definition, of the symbol in question.
Since these are clearly meant to be source files from two separate projects, I would suggest moving your definition to its own .cpp file which may then be shared between the two projects.
$ gcc a.c myIntPointerIsHere.c
$ gcc b.c myIntPointerIsHere.c
However, there are clearer ways to share code between two different projects.
The both modules contain the definition of main. It seems that the compiler did not include the first module in your project. Otherwise I think it would issue an error that main was redefined.