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.
Related
I'm new to strong & weak symbol concepts. For the following example (pure C) code, x is defined twice, one strong and one weak. I'd like to make my compiler report error:
foo.c:
#include <stdio.h>
void f(void);
int x = 15213;
int main(){
f();
printf("x = %d\n", x);
return 0;
}
bar.c
int x;
void f(){
x = 15212;
}
For gcc, "-fno-common" is what I want:
gcc -o foobar foo.c bar.c -fno-common
Thus it reports redefined symbols (x).
Is there an equivalent compile option in Visual Studio? (Correct me if I'm wrong described)
This is a link option: not a compile option. The compiler doesn't know anything about x being declared anywhere else except in the file it is compiling. The linker, however, sees two x declarations and will generate error 2005 or 1169.
I have three files, test.c, a.h, a.c. test.c call a function declared in a.h, and a.c define the function. But the funcion in a.c are different from a.h in the return value and the parameter. Either case, there is no warning from my gcc and there is some result. Why?
In my test.c
#include "a.h"
#include <stdio.h>
int main(){
int x = a();
printf("%d\n", x);
}
In my a.h
int a();
In my a.c
#include <stdio.h>
void a(int a)
{
printf("%d\n", a);
}
in my terminal:
$ gcc -o test test.c a.c // no warning
$ ./test
1
2
Without the a.h being included in a.c, the compiler doesn't know it's a problem. So you won't get any compile issues at all. Each gets its own .o file and everyone is happy.
The compiler expects a() to return an int so it has the machine code grab the result off the stack (or probably some register).
The compiler expects a() to have a parameter, so it has the machine code grab the parameter off the stack (again, probably a register).
Then the linker comes along and puts them all together. It doesn't know that there's an issue, but it makes the call to a() work.
So you get values that are left over on the register (or stack). And hopefully you're in a protected environment so that you're not getting some other user's information.
I was wondering how this works, creating a library and preloading it so a program can use it instead of the one in the include statement.
here is what I am doing and is not working so far .
//shared.cpp
int rand(){
return 33;
}
//prograndom.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
srand(time(NULL));
int i = 10;
while(i--) printf("%d\n", rand()%100);
return 0;
}
Then in the terminal:
$ gcc -shared -fPIC shared.cpp -o libshared.so
$ gcc prograndom.cpp -o prograndom
$ export LD_PRELOAD=/home/bob/desarrollo/libshared.so
and finally
$ LD_PRELOAD=/home/bob/desarrollo/libshared.so ./prograndom
which doesnt print 33, just random numbers...
Your programs are C programs, but the cpp file extension implies C++, and GCC will interpret it that way.
That's an issue because it means that your function rand (in shared.cpp) will be compiled as a C++ function, with its name mangled to include its type-signature. However, in main you #include <stdlib.h>, which has the effect of declaring:
extern "C" int rand();
and that is the rand that the linker will look for. So your PRELOAD will have no effect.
If you change the name of the file from shared.cpp to shared.c, then it will work as expected.
Other alternatives, of dubious value, are:
Declare rand to be extern "C" in your shared.cpp file. You can then compile it as C++.
Force compilation as C by using the GCC option -x 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.
My a.c file:
int sum(int a, int b) {
return a + b;
}
My b.c file:
#include<stdio.h>
extern int sum(int, int);
int main() {
printf ("%d", sum(2, 3));
return 0;
}
gcc a.c b.c -o output, working fine.
Let say tomorrow, I change the definition of "a.c file" sum function by increasing the argument to three. Like this,
int sum(int a, int b, int c) {
return a + b + c;
}
But forget to change the usage in b.c file (means I'm still using with two variable)
gcc a.c b.c -o output (doesn't give compilation error or warning mssg, printf gives wrong answer, obviously)
Now consider I'm working in huge set of c file and I cannot make new header file, because it will create unnecessary dependency problem which may take huge time to resolve.
What is the best way to throw error or even warning message in case the extern original definition is changed in terms of argument ?
Regards
What is the best way to throw error or even warning message in case the extern original definition is changed in terms of argument?
Neither compiler nor linker will object to that. You'll just find out at runtime (if you are lucky) when your program stops working.
If this was C++ then name mangling would allow the linker to reject such mal-formed programs. However, for C the linker only needs to find a symbol with the right name. It has no means of checking the signature.
Using header files is the accepted way to get the compiler to make sure you do things right. Repeating function declarations over and over throughout your program is usually a very bad idea. Whatever downsides you perceive to using header files pale into insignificance when compared to your proposed approach.
If you simply won't use header files, then you'll just have to always be right!
Normally editors like (SourceInsight,Sublime) have the options to browse the symbols. By using this option you can easily find function calls and prototype.
Compiler never generate warnings or error for your problem.Self contained header files are best option to avoid this situation.
The best thing to do is try to avoid "extern" and include the header file for sum(). Using header files and prototyping your functions will help the compiler catch these issues.
test.c:
#include <stdio.h>
#include "math.h"
int main(void)
{
printf("%d", sum(2, 3));
return 0;
}
math.h:
int sum(int a, int b, int c)
{
return (a + b + c);
}
output:
~]$ gcc test.c -o test
test.c: In function ‘main’:
test.c:6:5: error: too few arguments to function ‘sum’
printf("%d", sum(2, 3));
^
In file included from test.c:2:0:
math.h:1:5: note: declared here
int sum(int a, int b, int c)