• AVR Freaks

Helpful ReplyHot!multiply defined symbols

Author
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
2019/05/20 01:50:25 (permalink)
0

multiply defined symbols

If you have a declaration of a variable in a header file, and this header file is included in several c files, the linker complains that there are multiply defined symbols. Right? This is basic knowledge. But you know what? It does not seem to work that way anymore with some compilers/linkers (Visual Studio, MPLab xc32). You can define a same-named, but global (not static) variable in two c files, write to it in one of the files and read from it in the other file and get the value that you wrote in the first file. Not only does the linker not complain but it actually places the variable in one position only!!! Is this a recent development? By the way, the variable does not need to be declared in a header file for this to happen. Just declare the same variable in two c files.
 
Anybody has any idea whether compilers/linkers have changed practise on this issue? This could have some serious ramifications.
#1
qhb
Superb Member
  • Total Posts : 9998
  • Reward points : 0
  • Joined: 2016/06/05 14:55:32
  • Location: One step ahead...
  • Status: offline
Re: multiply defined symbols 2019/05/20 02:08:55 (permalink)
+1 (1)
Mr.Mxyzptlk2620
If you have a declaration of a variable in a header file, and this header file is included in several c files, the linker complains that there are multiply defined symbols. Right?

Wrong.
If you got an error, then you had a "definition" not a "declaration".
 
Also, you are not clear if you are talking about C or C++.

Nearly there...
#2
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 02:30:30 (permalink)
0
Actually, I just put "int dummytest;" in two c (not c++) files. In the first file, I set dummytest to 1. In the second file, I printed dummytest, and it was 1. And looking at the dummytest variable, it had the same address in the two files. What is even more alarming is that if I assigned the dummytest variable to an initial value (like int dummytest = 0 in the first c file, and int dummytest = 2 in the second file), the value read by the debugger before I set it to 1, was 0. How did the linker decide to go with the first initial value and not the second? And for the sake of completeness, if you put "int dummytest;" in a header file that will turn up as a declaration in a c (not c++) file.
 
I am also speechless!!!
#3
andersm
Super Member
  • Total Posts : 2621
  • Reward points : 0
  • Joined: 2012/10/07 14:57:44
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 03:00:35 (permalink)
+1 (1)
Mr.Mxyzptlk2620And for the sake of completeness, if you put "int dummytest;" in a header file that will turn up as a declaration in a c (not c++) file.

No, that's a definition. A declaration would be "extern int dummytest;". Trying to initialize a global variable twice is an error. It would be better if the linker generated an error message, but you can't reason about correct behaviour of invalid code.
#4
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 03:32:06 (permalink)
0
The point I am trying to make here is that there are two variables with the same name in two c files, and the linker not only allows it but allocates the two on one location only. This means that if you accidentally name a variable in one c file the same as a variable in another c file, you will get all sorts of funny runtime errors, as you won't have the linker error to tell you that it is the same variable.
 
I do believe that either this is a grave error or an undocumented feature of the compiler/linker that everybody should be made aware of, and I apologize if this is now common knowledge but any colleague of mine I've told this to is as flabbergasted as me.
 
#5
andersm
Super Member
  • Total Posts : 2621
  • Reward points : 0
  • Joined: 2012/10/07 14:57:44
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 04:09:46 (permalink) ☄ Helpfulby moser 2019/05/20 05:43:16
+1 (1)
The C99 standard mentions this as a "common extension" to the language:
J.5.11 Multiple external definitions
There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).

I would assume it's possible to generate a warning or error in this case, but I don't know what compiler or linker option to set offhand; check the documentation.
#6
qhb
Superb Member
  • Total Posts : 9998
  • Reward points : 0
  • Joined: 2016/06/05 14:55:32
  • Location: One step ahead...
  • Status: offline
Re: multiply defined symbols 2019/05/20 04:21:24 (permalink)
0
Add "static" to the definition if you want to make sure each C file gets its own private copy.
 

Nearly there...
#7
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 04:34:52 (permalink)
0
Thanks. I stand corrected.
 
I am obviously not up-to-date with the latest C standard (I started programming more than 30 years ago). But I have noticed in other forums that a lot of people thought the same as me, so maybe news about this feature should be more widespread. I, for one, have always avoided using global variables. Instead, I usually implement global access functions if needed, and I make sure their names are unique.
 
What triggered me was some code from another vendor that had the definition of a variable in a header file that was included in several c files. The apparent assumption was that the source code in the c files was referring to the same variable, and now it turns out it was correct.
 
Well, you live and learn..
#8
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 05:18:16 (permalink)
0
One last thing.
 
I am sure that some old geezer out there like me would be inventing variable names out of the top of his head in his own "personal space", even making them global on purpose, not bothering to check whether the same name was being used in the myriad of other source files that huge projects usually consist of, either written in-house or as other vendor code (like Microchip). That old geezer would be expecting to be hit by a linker error like in the old days if he wasn't being original enough.
 
That's all changed now - you need to have the discipline to check and double-check before you commit yourself to a global name! No trial-and-error here.
 
#9
Jim Nickerson
User 452
  • Total Posts : 6128
  • Reward points : 0
  • Joined: 2003/11/07 12:35:10
  • Location: San Diego, CA
  • Status: offline
Re: multiply defined symbols 2019/05/20 06:05:21 (permalink)
0
I make it a practice to always init my variables to a value when declared.
#10
moser
Super Member
  • Total Posts : 490
  • Reward points : 0
  • Joined: 2015/06/16 02:53:47
  • Location: Germany
  • Status: offline
Re: multiply defined symbols 2019/05/20 06:24:48 (permalink)
+1 (1)
I also wasn't aware of this. What I just learned is that if you have multiple definitions in the same compile unit, then it is called a "tentative definition".
 
If you have it across compile units it is an "external definition for the identifier of an object, [...] without the explicit use of the keyword extern". As andersm has already shown in post #6, it is an extension ( J.5.11 ) to the C compiler. I have read several warnings that you should not trust that it is supported everywhere, and you might want to avoid it, if you want to have portable code.
 
However, the really sad thing about this extension is the sentence "if the definitions disagree, or more than one is initialized, the behavior is undefined" instead of "[...] the compiler will call you a stupid developer and reject everything".
 
 
Some stuff to read about this:
http://c0x.coding-guidelines.com/6.9.2.html
https://stackoverflow.com...ative-definitions-in-c
https://stackoverflow.com...s-between-source-files
 
 
About the warning, well, there is ...
-Wredundant-decls
Warn if anything is declared more than once in the same scope, even in cases where
multiple declaration is valid and changes nothing.

... and as far as I know it is not included in -Wall. But this is not what we need, because this is about declarations instead of definitions.
#11
aschen0866
Super Member
  • Total Posts : 4481
  • Reward points : 0
  • Joined: 2006/01/08 22:18:32
  • Location: San Diego
  • Status: offline
Re: multiply defined symbols 2019/05/20 07:11:22 (permalink)
+1 (1)
moser
I also wasn't aware of this. ...


You aren't the only one. I asked the same question 7 years ago.
 
https://www.microchip.com/forums/m625820.aspx
 
 
#12
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 07:48:24 (permalink)
+1 (1)
I just checked my old Kernighan Ritchie, second edition. In chapter A10.2, it describes this phenomenon. And that edition predates the C99 standard.
 
I do seem to recall being hit by multiply definitions errors back in the day but maybe I was not paying attention to what exactly caused the linker errors. Probably, the global variables were initialized to different values.
 
Anyway, that taught me a lesson that I shouldn't use global variables but instead encapsulate all access in global functions with unique names.
 
But I do know that the trial-and-error approach of naming a variable and expecting the linker to save you is quite common still, especially in large projects with lots of vendor code which makes it even more worrisome. Unintended name matching in a preemptive multitasking system can lead to all sorts of runtime errors.
#13
andersm
Super Member
  • Total Posts : 2621
  • Reward points : 0
  • Joined: 2012/10/07 14:57:44
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 08:01:38 (permalink)
+2 (2)
 
Mr.Mxyzptlk2620But I do know that the trial-and-error approach of naming a variable and expecting the linker to save you is quite common still, especially in large projects with lots of vendor code which makes it even more worrisome.

Since the rule is that the definitions must be identical, you could make it a rule to first try with some type guaranteed to be unique.
#14
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/20 08:16:44 (permalink)
0
That rule of identical definition must have eliminated a lot of unintended name matching in the past, for sure. And it's a good idea going forward.
 
 
But there is still this lingering doubt that sometimes the widespread use of trial-and-error has created problems in the past for projects noone is aware of. People didn't always bother to use static for variables that were not intended to be global.
#15
JasonK
Moderator
  • Total Posts : 3383
  • Reward points : 0
  • Joined: 2003/11/14 09:49:40
  • Location: Microchip Technology in Arizona, USA
  • Status: offline
Re: multiply defined symbols 2019/05/20 09:55:48 (permalink) ☄ Helpfulby moser 2019/05/21 02:47:57
+3 (3)
You should be able to disable this behavior using the -fno-common xc32-gcc/g++ option.
 

Jason Kajita
 Follow me on Twitter
http://support.microchip.com for urgent questions
#16
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/21 00:47:15 (permalink) ☄ Helpfulby moser 2019/05/21 02:19:16
+2 (2)
I couldn't find -fno-common but I did find --warn-common (xc32-ld option).
 
I tested it and this option is exactly what I need.
 
I am also going to do a sanity check on some older projects with this option just to see whether I can unearth some potential problems.
#17
moser
Super Member
  • Total Posts : 490
  • Reward points : 0
  • Joined: 2015/06/16 02:53:47
  • Location: Germany
  • Status: offline
Re: multiply defined symbols 2019/05/21 02:47:51 (permalink)
+1 (1)
Thanks, JasonK and Mr.Mxyzptlk2620. This is helpful.
 
Both ways work for me, but be aware that one is a compiler option, and the other a linker option. This link explains both -fno-common and --warn-common:
https://stackoverflow.com...al-variables-of-same-s
 
This is an example output for compiler option -fno-common (at xc32-gcc, Additional Options):

build/MYPROJECT/production/_ext/1360937237/myfile.o:(.sbss+0x0): multiple definition of `myvariable'
build/MYPROJECT/production/_ext/1360937237/myotherfile.o:c:/microchip/harmony/v2_03b/apps/myconfig/firmware/src/myotherfile.c:92: first defined here
c:\program files (x86)\microchip\xc32\v1.42\bin\bin\gcc\pic32mx\4.8.3\..\..\..\..\bin/xc32-ld.exe: Link terminated due to previous error(s).
collect2.exe: error: ld returned 255 exit status

 
This is an example output for the linker option --warn-common (at xc32-ld, Additional Options):

Dynamic Data-Memory Reservation
section address length [bytes] (dec) Description
------- ---------- ------------------------- -----------
heap 0xWHATEVER 0xSIZE SIZE Reserved for heap
stack 0xWHATEVER 0xSIZE SIZE Reserved for stack
--------------------------------------------------------------------------
"C:\Program Files (x86)\Microchip\xc32\v1.42\bin"\\xc32-bin2hex dist/MYCONFIG/production/MYPROJECT.X.production.elf
build/MYCONFIG/production/_ext/1360937237/myfile.o: warning: common of `myvariable' overridden by definition
build/MYCONFIG/production/_ext/1360937237/myotherfile.o: warning: defined here
make[2]: Leaving directory 'C:/microchip/harmony/v2_03b/apps/MYPROJECT/firmware/MYPROJECT.X'
make[1]: Leaving directory 'C:/microchip/harmony/v2_03b/apps/MYPROJECT/firmware/MYPROJECT.X'
BUILD SUCCESSFUL (total time: 1m 15s)

This one actually still builds. If you don't want that, you can use --fatal-warnings.
#18
Mr.Mxyzptlk2620
Starting Member
  • Total Posts : 52
  • Reward points : 0
  • Joined: 2015/09/16 07:50:53
  • Location: 0
  • Status: offline
Re: multiply defined symbols 2019/05/21 04:59:14 (permalink)
+1 (1)
Thanks for clearing that up.
 
I think I am going to stick with the warning purely because you never know whether the vendor code relies on the usage of common variables, and, if your code does not reference those variables, you still want the damn thing to be built.
#19
Jump to:
© 2019 APG vNext Commercial Version 4.5