Redefinition error #ifndef code isn't working

General discussion on mikroC PRO for ARM.
Author
Message
jemmicat
Posts: 24
Joined: 20 Mar 2012 13:47

Redefinition error #ifndef code isn't working

#1 Post by jemmicat » 19 May 2012 23:25

I have been banging my head for over a week trying to get some code to work. I finally narrowed it down and realized that one of the header files is not getting excluded when it is called from within another program. I did some research on here and it seems several of the older version of the PIC C compiler had the same problem. Is this being workd on? As when I try to define everything with the work around I found on here, using the extern function call, then I get unresolved extern function call. This is extremely annoying and is a mjor problem with my getting my project done. Please correct in new release!

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Redefinition error #ifndef code isn't working

#2 Post by filip » 21 May 2012 13:55

Hi,

Please, can you attach you project here for the inspection ?

Regards,
Filip.

jemmicat
Posts: 24
Joined: 20 Mar 2012 13:47

Re: Redefinition error #ifndef code isn't working

#3 Post by jemmicat » 21 May 2012 18:13

I am trying to get this gps test program to compile. If I include the TinyGPS.c file in the compile, it shows a redefinition. If I don't include it, it shows the get_position function and others not able to be externally resolved. I added the gps.h file calling out the external functions and again get the redefinition. It is NOT excluding the TinyGPS.h file both times which is why I get the redefinition errors. From the research I did, apparently the same problem was in the MikroC PIC compilers last fall.

Maybe I am doing something wrong, but I just don't think so. I don't know why it is doing this

The main function isn't complete. I have been adapting this code and it had other functions in it that I didn't need. I have been working my way through and changing what needs changed to get it to compile. I have not been able to get past this issue so I haven't been able to compile the code and add in the outputs I want. I am trying to get this working to verify working of the GPS prior to adding the TinyGPS.c and .h files to my logger program.
Attachments
testgps.rar
(88.34 KiB) Downloaded 383 times

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Redefinition error #ifndef code isn't working

#4 Post by filip » 22 May 2012 10:58

Hi,

I see your issue now. You have defined the functions in the header file and included that header in both source (.C) files.
Instead, you should have put the definition of each function in the separate source file and put the function declarations in the header file, like in the sample project from the attachment.

Regards,
Filip.
Attachments
testgps.rar
(1.94 KiB) Downloaded 673 times

jemmicat
Posts: 24
Joined: 20 Mar 2012 13:47

Re: Redefinition error #ifndef code isn't working

#5 Post by jemmicat » 22 May 2012 13:56

But why? My understanding is that the #ifndef is basically saying that if this file is already included, then don't include it. That is how I understand that to work after much research. but it DOESN'T work that way on MikroC. Why? Other compilers I looked into work that way... Why not MikroC? Why do I have to jump through hoops like this to use the software (which I DO like as it is laid out in a way easy for me to understand) when I wouldn't have to if I switched to another compiler? I just don't understand why this simple concept can't be done in MikroC how it is with most of the other compilers

Mince-n-Tatties
Posts: 2780
Joined: 25 Dec 2008 15:22
Location: Scotland

Re: Redefinition error #ifndef code isn't working

#6 Post by Mince-n-Tatties » 28 May 2012 13:41

yip it is a real pain and impacts code port.

thing is that include guarding works perfectly in mikroC with a single .c and multiple .h files where the .c can include every .h and each .h can include any other .h

but as soon as you have a second .c which introduces a second instance of including a .h then bang it all falls apart as if the include guard has been ignored.

It would be great if the mE guys could fix this.
Best Regards

Mince

synvox
Posts: 3
Joined: 29 May 2012 16:46

Re: Redefinition error #ifndef code isn't working

#7 Post by synvox » 29 May 2012 17:40

This is actually a completely correct behaviour of a C compiler/linker. In another forum Simon Ford (from ARM company) explained this in a very comprehensive way to a user (Mama), who complained about a similar case with the behaviour of another C-Compiler (from a large and known company):
Hi Mama,

If you are doing what I think you are, then this actually sounds like expected behaviour. I suspect you are not telling the compiler to do quite what you think you are :)

My guess is you have something that distills down to:

foobar.h

Code: Select all

#ifndef FOOBAR_H
#define FOOBAR_H
int x;
#endif
foo.cpp

Code: Select all

#include "foobar.h"
bar.cpp

Code: Select all

#include "foobar.h"
Yet you get:
Symbol x multiply defined (by foo.o and bar.o)

So why should this give an error? Surely the #ifndef means x only gets included once? It has always worked before! Well, now you have a choice...

You can take the blue pill. You've seen these #ifndef, #includes and header files used like this before. You know it should work. Stupid compiler. So just fiddle a bit until the compiler stops complaining. Continue a happy life with a blissful illusion of how a compiler goes about its job. You can ignore the occasional glitch.

Or you can take the red pill. You sense the compiler isn't doing what you thought it should for some reason. In fact, you worry it never has. But do you really want to know what all these things actually mean? You can't go back.

Take the red pill:

First, an explanation of how C compilers and the C pre-processor actually work, and how multiple definition problems can occur, which will hopefully start to make it more clear:

A really obvious case; you define the variable twice in the same source (.c/.cpp) file!

main.cpp

Code: Select all

int x;
int x;
int main() {}
variable "x" has already been defined in file "/main.cpp"

Hopefully, this one is pretty obvious! The compiler catches this when it looks at the source file.

The next common one would be based on two source files having the same variable:

main.cpp

Code: Select all

int x;
int main() {}
other.cpp

Code: Select all

int x;
Symbol x multiply defined (by main.o and other.o)

In this case, the error is slightly different. Notice it doesn't refer to a particular source file this time; in fact, it refers to two different object files. To understand this, lets explain a little more of what goes on when you compile a program; the compiler goes through two stages:
* Independently translate each .c/.cpp source file to a corresponding .o assembly object file (compiling)
* Combine all the different .o object files in to one .bin binary image (linking)

So first the compiler compiles main.cpp to main.o, and that is fine. Then it tries to compile other.cpp to other.o, and because the compilation is independent, that is also fine; it doesn't know anything about the "x" in the other source file. But then when the linker tries to combine all the object files together to make the final binary image, it falls over, because it has two variables named "x" which is not allowed.

So these two examples show the underlying reason for multiply defined symbol errors, the difference between a compile time and link time errors, and how to distinguish them from the error message.

In these examples, the problem is fairly obvious, and it is clear why the computer says no. Where people often become unstuck is when the C pre-processor and header files join the party.

In our case, we had the #ifndef's to ensure these errors didn't happen. So why didn't that work?

Well, as in this case, it is simply a slight misunderstanding of how compilers, header files and the c pre-processor actually work. Like a lot of things, it is simple when you know how, and therefore why.

When compiling a source file, it is first passed to the c pre-processor to manipulate the file in useful ways before it is compiled; this is to do things like define variables used later in that file (#define), conditionally skipping/processing bits of the file (#ifdef, #ifndef), and including other files (#include). You can think of #include as just copying the referenced file and pasting it in the place the #include appears. For more details on the C pre-processor, see:
http://en.wikipedia.org/wiki/C_preprocessor

So lets look at that code again:

foobar.h

Code: Select all

#ifndef FOOBAR_H
#define FOOBAR_H
int x;
#endif
foo.cpp

Code: Select all

#include "foobar.h"
bar.cpp

Code: Select all

#include "foobar.h"
The mistake become clear if you think about two important points we've covered:
# Each .c/.cpp file is being compiled independently
# The preprocessor is simply modifying that single .c/.cpp file before passing it to the compiler

So when the compiler compiles foo.cpp, it includes the contents of foobar.h in it because of the include. And FOOBAR_H hasn't been defined, so it is defined and x is included. But when the compiler now independently goes and compiles bar.cpp, exactly the same thing happens. So both foo.o an bar.o contain x. And hence we get the link error.

Hope that helps!

Simon Ford
So if you really need to make a variable or function known in two different .c/.cpp files, you should define it only in one and use the keyword "extern" in the other to make it known in that file (i.e.=> extern int x;).

Best regards
Neni

Mince-n-Tatties
Posts: 2780
Joined: 25 Dec 2008 15:22
Location: Scotland

Re: Redefinition error #ifndef code isn't working

#8 Post by Mince-n-Tatties » 30 May 2012 20:26

i use ARM tools and there is no problem with multiple .c files having multiple ref to multiple .h files. all working fine when include guard technique is used.

i cant show the code details but i can show enough to prove it works with ARM tools.
first.jpg
first.jpg (112.51 KiB) Viewed 12014 times
lcd.jpg
lcd.jpg (110.69 KiB) Viewed 12014 times
util.jpg
util.jpg (111.5 KiB) Viewed 12014 times
Best Regards

Mince

Mince-n-Tatties
Posts: 2780
Joined: 25 Dec 2008 15:22
Location: Scotland

Re: Redefinition error #ifndef code isn't working

#9 Post by Mince-n-Tatties » 30 May 2012 20:40

ser_h.jpg
ser_h.jpg (109.23 KiB) Viewed 12013 times
build.jpg
build.jpg (28.28 KiB) Viewed 12013 times
there are numerous functions in various .h files which i created and said .h files are being included in numerous .c files.

now i dont do much PC software (i do the embedded side and only really do PC side when i need a specific test tool) but i work with people that only do pc software, i asked those guys the exact question "should i be able to have multiple .c files each with a ref to the same multiple .h files"?

answer... so long as you use include guarding then of course, we do it everyday and wouldnt be able to work modularly (with remote coders) if we couldnt.

i have used many ARM compilers from various manufacturers and never had a problem solving this issue with the use of include guarding.
Best Regards

Mince

synvox
Posts: 3
Joined: 29 May 2012 16:46

Re: Redefinition error #ifndef code isn't working

#10 Post by synvox » 31 May 2012 12:02

One should destinguish between declaration and definition of resources. Of course there is no problem, if you include the same .h files in different .c files, if in the .h files you have only function declarations and no function definition. A declaration makes just the function name known to the compiler and doesn't reserve any ram and/or flash resources. Then the linker has no problem, because the different .o files haven't defined the same resources.

Mostly the problem occurs with variables, because if you write for example "int x;" even without an initialisation value, most compilers already reserve the needed space in ram in the resulting .o file, so it's actually a definition. The #ifndef won't help here either, because as explained before, it only has an effect in one and the same .c file. So for variables the rule is to put them in the .c files and use the "extern" keyword (explicite declaration) in the other .c files, if the same variable has to be known in these too.

But the thread starter had a problem with functions, because he did define the functions in the .h file and not just declare them there. So if he includes that .h file in two different .c files, he gets two .o files with resources reserved for the same function name in both, even when using #ifndef in the .h file, because of the independent compilation of the .c files. So the linker afterwards stops with the multiple definition error.

I hope this made it a little bit clearer.

Best regards
Neni

jemmicat
Posts: 24
Joined: 20 Mar 2012 13:47

Re: Redefinition error #ifndef code isn't working

#11 Post by jemmicat » 31 May 2012 15:05

I work with someone who has been coding C for 20+ years for embedded and PC applications for industrial use and he also had not seen any compiler have the issue that the mikroC issue has with not actually using the guarding (Although the compiler complains quite loudly about not having the guarding if you remove the guarding and still refer to the header file with 2 .c files... It's like it knows what it is but just doesn't use it)

Mince-n-Tatties
Posts: 2780
Joined: 25 Dec 2008 15:22
Location: Scotland

Re: Redefinition error #ifndef code isn't working

#12 Post by Mince-n-Tatties » 01 Jun 2012 14:17

synvox wrote: and no function definition.
there are many many function definitions in my .h files :D
Best Regards

Mince

User avatar
rajkovic
mikroElektronika team
Posts: 694
Joined: 16 Aug 2004 12:40

Re: Redefinition error #ifndef code isn't working

#13 Post by rajkovic » 01 Jun 2012 15:07

multiple function definitions are not allowed
preprocessor works upon each c without knowing what is in another C file.
Yet there is one thing where mikroC acts more like C++ than C it is tentative definition of variables, it reports error
if you have more than one tentative definition and most c compilers does not do this.
Here opinions are divided but probably we will allow this.


had tried mince another vendor and made small project and it reported error of multiple definition. I think that as far as
#ifdef preprocessor and function definition everything works as it should by the book
Attachments
log.jpg
log.jpg (73.08 KiB) Viewed 11951 times

Mince-n-Tatties
Posts: 2780
Joined: 25 Dec 2008 15:22
Location: Scotland

Re: Redefinition error #ifndef code isn't working

#14 Post by Mince-n-Tatties » 01 Jun 2012 20:16

Hi rajkovic

thanks for taking the time to investigate. okay thats fine with me, it is a minor pain which i can continue to work around with minimal effort.
Best Regards

Mince

jemmicat
Posts: 24
Joined: 20 Mar 2012 13:47

Re: Redefinition error #ifndef code isn't working

#15 Post by jemmicat » 01 Jun 2012 22:15

unfortunately it is a major pain for me but I will have to deal with it. Trying to get that ported library to play nice within MikroC is not working nicely. It was written to compile with MPLab for AVR. That compiler had no issues with ANY of it as it was written. Although I've read ALL of this and understand what you're saying, I do not know WHY MikroC is complaining about the code when every other compiler (IAR, Keil, MPLab) seem to have no issues. Right coding, wrong coding is irrelevant to me. What matters to me is that I cannot take code that works everywhere else and use it with MikroC without MAJOR changes. I just don't get that. I tried AGAIN to get it to the format that MikroC seems to want and the code falls apart... I have wasted far too much valuable coding time on my project fighting a "quirk" of MikroC that I wouldn't have to deal with with any other compiler. It just makes no sense to me.

I will probably just have to move on to another compiler. Coding is not my primary skill (I am a mechanical engineer trying to port my project over from Arduino to utilize the faster processor and 32 bit architecture). I have a working, but slow, version now. I guess I expected MikroC to work like other compilers I've used. Apparently that is where I went wrong. Wasted $250 it seems...

Post Reply

Return to “mikroC PRO for ARM General”