gcc generate wrong C symbol from C++ source file
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
GNU Arm Embedded Toolchain |
New
|
Undecided
|
Unassigned |
Bug Description
My test project has 3 files: main.cpp, test01.c, test02.cpp
test01.c ===>
#include <stdint.h>
const uint32_t testMaxDataLength = 16;
const uint8_t testMaxData[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
};
test02.cpp ==>
#include <stdint.h>
const uint32_t testCplusplusDa
0x01234567, 0x89ABCDEF, 0xFFFF0000, 0x0000FFFF
};
#ifdef __cplusplus
extern "C" {
#endif
const uint32_t testCDatap[2] = {
0xFFFFFFFF, 0x00000000
};
#ifdef __cplusplus
}
#endif
main.cpp ===>
#include <stdint.h>
extern const uint32_t testCplusplusDa
#ifdef __cplusplus
extern "C" {
#endif
extern const uint32_t testMaxDataLength;
extern const uint8_t testMaxData[16];
extern const uint32_t testCDatap[2];
#ifdef __cplusplus
}
#endif
void main(void) {
uint32_t total = 0;
for (uint32_t i = 0; i < 4; i++) {
total += testCplusplusDa
}
for (uint32_t i = 0; i < testMaxDataLength; i++) {
total += testMaxData[i];
}
for (uint32_t i = 0; i < 2; i++) {
total += testCDatap[i];
}
}
the gcc toolchain will report "undefined reference to `testCplusplusD
use arm-none-eabi-nm check test02.cpp.o, test01.c.o, main.cpp.o:
00000000 r _ZL10testCDatap
00000000 r _ZL18testCplusp
00000000 R testMaxData
00000000 R testMaxDataLength
U testCDatap
U testCplusplusDatap
U testMaxData
U testMaxDataLength
the _ZL10testCDatap is not C symbol. and main link require No C++ symbol testCplusplusDatap.
ARM-NONE-EABI-GCC version : arm-none-eabi-gcc (GNU Arm Embedded Toolchain 9-2020-q2-update) 9.3.1 20200408 (release)
compiler & Linker flags:
C++ & C common flags ==>
"-Wall",
"-Wextra",
"-mthumb",
"-MMD",
C flags ===>
C++ flags ==>
linker flags ==>
"-mthumb",
"-Wall",
"-Wextra",
"-g3",
"-Xlinker",
In C++, the default linkage for a "const" declaration is internal. This is different from non-const declarations, and different from C (or C++ with extern "C"), where the default linkage is external. So if you declare an object in a C++ file as "const uint32_t testCplusplusDa tap[4] = {..." , then it it has internal linkage - the symbol is not exported from the current file.
There is nothing wrong with the names here, it is simply that the const symbol is left internal to the C++ file.
The quick solution is to add "extern" to the definition of the C++ const array.
The correct solution is to use headers, and be strict in making all your "extern" declarations in a header, while the C or C++ file #include's the matching header and has the definitions of the objects. Any objects that don't have a declaration in the header should be "static", if they are not C++ const objects. The use of the keyword "extern" within a C or C++ file, rather than a header, should therefore be a sign of questionable code structure.
(There are always exceptions to such rules - including quick tests.)