No compile error regarding wrong function parameters - c

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.

Related

dlsym - "Too many arguments to function" error

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.

Why do I need headers?

I have simple program 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(int i)
{
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 $# $<
Program builds fine and runs, but in count_words.c I didn't include header file with function int aaa(int) declaration from clean.c . Why I need to have header file at all since I have no problem to compile program without them?
Header files usually contain the function declarations which serves as the forward declaration. Without having the function forward declaration, any call to a function is considered implicit declaration of the function.
As on C99 standard onward, implicit declaration of a function has been made non-standard. Compilers may support this for legacy code support, but it's not guaranteed to have this in future.
So the bottom line is, you need to have the function declarations in each of the source files. While using a a header file, we can club all the forward declarations and with a single include statement per source file we can have all of them included in each of the sources.
Thus from the usability point of view, you don't need to repeat the individual declarations in each and every source file when you include the header file. This supports DRY principle, so it is good.

No parameter checking in GCC

I have written a C program, which consists below given three files in same directory
main.c
#include<stdio.h>
#include "test.h"
int main()
{
int b=0;
b = test_add(3,2);
printf("Added: b=%d\n\n",b);
return 0;
}
test.h
int test_add(int a, int b);
test.c
int test_add(int a, int b, int c)
{
return a+b+c;
}
I am compiling the program using below command:
$gcc -Wall -Wextra main.c test.c
It compiles successfully. I can see there is mismatch in number of arguments of calling function and its actual definition. Compiler doesn't give any warning/error for such problem. How can this type of errors be reported by compiler?
This shows one of the oddities of the C standard. It allows entities such as functions to be undefined.
The actual error is that you did not
#include "test.h"
in you test.c file.
That means that the main file only sees the version of the function with three parameters. When it reaches the function call, it implicitly declares the function with two parameters.
When you run it, you get bogus values for b. I am guessing the superuser's password could somehow be in there ;)
If you add the include directive, you get an error at compile time.
What worries me, that there is no warning, not even with -Wall -Wextra -pedantic.

How to change the name of executable entry point from main to something else?

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.

warning: data definition has no type or storage class = flite compilation warning

vi example.c
#include<stdio.h>
#include "flite.h"
register_cmu_us_kal();
int main(int argc,char** argv)
{
cst_voice *v;
if(argc!=2)
{
fprintf(stderr,"usage:file_test FILE\n");
exit(-1);
}
flite_init();
v=register_cmu_us_kal(NULL);
flite_file_to_speech(argv[1],v,"play");
return 0;
}
Compile:
desktop:
~/flite-1.4-release$ gcc example.c -I./include/ -L./build/i386-linux-gnu/lib -lflite -lflite_cmu_us_kal -lflite_cmulex -lflite_usenglish -lflite_cmu_us_rms -lflite_cmu_time_awb -lflite_cmu_us_slt -lflite_cmu_us_awb -lm -o example
example.c:3: warning: data definition has no type or storage class
example.c: In function ‘main’:
example.c:13: warning: assignment makes pointer from integer without a cast
I have explored the contents of the lib folder below.
desktop:
~/flite-1.4-release$ ls
ACKNOWLEDGEMENTS config.guess configure example flite.sln lang mkinstalldirs src wince
bin config.log configure.in example.c -I main palm testsuite windows
build config.status COPYING Exports.def include Makefile README test.txt
config config.sub doc fliteDll.vcproj install-sh missing sapi tools
desktop:
~/flite-1.4-release/build/i386-linux-gnu/lib$ ls
libflite.a libflite_cmu_us_awb.shared.a libflite_cmu_us_kal.so.1 libflite.shared.a
libflite_cmulex.a libflite_cmu_us_awb.so libflite_cmu_us_kal.so.1.4 libflite.so
libflite_cmulex.shared.a libflite_cmu_us_awb.so.1 libflite_cmu_us_rms.a libflite.so.1
libflite_cmulex.so libflite_cmu_us_awb.so.1.4 libflite_cmu_us_rms.shared.a libflite.so.1.4
libflite_cmulex.so.1 libflite_cmu_us_kal16.a libflite_cmu_us_rms.so libflite_usenglish.a
libflite_cmulex.so.1.4 libflite_cmu_us_kal16.shared.a libflite_cmu_us_rms.so.1 libflite_usenglish.shared.a
libflite_cmu_time_awb.a libflite_cmu_us_kal16.so libflite_cmu_us_rms.so.1.4 libflite_usenglish.so
libflite_cmu_time_awb.shared.a libflite_cmu_us_kal16.so.1 libflite_cmu_us_slt.a libflite_usenglish.so.1
libflite_cmu_time_awb.so libflite_cmu_us_kal16.so.1.4 libflite_cmu_us_slt.shared.a libflite_usenglish.so.1.4
libflite_cmu_time_awb.so.1 libflite_cmu_us_kal.a libflite_cmu_us_slt.so
libflite_cmu_time_awb.so.1.4 libflite_cmu_us_kal.shared.a libflite_cmu_us_slt.so.1
libflite_cmu_us_awb.a libflite_cmu_us_kal.so libflite_cmu_us_slt.so.1.4
Please help me to fix this problem.
The following declares a function that takes unspecified arguments and returns an int:
register_cmu_us_kal();
When you call it, you assign its result to a variable of type cst_voice*:
v=register_cmu_us_kal(NULL);
The compiler warns you about this conversion.
I think the best course of action is to provide a proper prototype for register_cmu_us_kal (perhaps by including the relevant header file).
You can fix this by changing your method declaration:
register_cmu_us_kal();
To
cst_voice *register_cmu_us_kal();
This tells the compiler that the method
register_cmu_us_kal(); returns a cst_voice * instead of an int which is the default, which, when you assign this:
v = register_cmu_us_kal(NULL);
First, you are calling the function with parameters where you define it without parameters, secondly it is warning you that you are trying to assign a int to a cst_voice *.

Resources