This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

extern "C" not understood by g++ ?

Other Parts Discussed in Thread: MSP430F5529, MSP430G2553

Hi,

I hope this is the right forum for my question. If not, please redirect me to the proper place.

We're using this gcc toolchain version 1_01_00_00 on Windows 7 x64 (with eclipse and msys make):
http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/latest/index_FDS.html

We want to use C++ instead of C, but the compiler complains about the >>extern "C"<< statement:


msp430-elf-g++ "-IC:\\devel\\toolchains\\msp430-ti-1.01\\include" -O0 -g3 -Wall -c -fmessage-length=0 -mmcu=msp430f5529 -mlarge -o main.o "..\\main.cpp" 

In file included from C:\devel\toolchains\msp430-ti-1.01\include/msp430f5529.h:63:0,
                 from ..\main.cpp:1:
C:\devel\toolchains\msp430-ti-1.01\include/iomacros.h:50:32: error: expected unqualified-id before string constant
     #define sfrb_(x,x_) extern "C" volatile unsigned char x asm(#x_)
                                ^


A dirty workaround is to remove the >>extern "C"<<, then the project compiles fine. But I cannot mix C with C++ code because the compiler doesn't seem to understand the >>extern "C"<< statement.

Any ideas?

Thanks
Christoph

  • I suggest you try a minimal test program with a simpler use of extern "C", just to narrow down where the issue lies.

    A single extern "C" function defined/declared in a .cpp/.h pair (compiled as C++), and called from a main function in a separate file compiled as C should help clarify what's going on.

  • Thanks for your suggestion.

    1. Compiling a simple C / C++ mixture as you suggested worked fine. I guess then the problem lies in the file iomacros.h.

    2. Switching on extra warnings revealed that 'extern' is not at beginning of declaration [-Wold-style-declaration]

    3. Found the bug and a workaround :-)

    Here's what's going on: Apparently extern "C" needs to be the first statement on the line or at least come before the const keyword. But on these lines in iomacros.h (close to the end) ...

    #define const_sfrb(x,x_) const sfrb_(x,x_)
    #define const_sfrw(x,x_) const sfrw_(x,x_)
    #define const_sfra(x,x_) const sfra_(x,x_)
    #define const_sfrl(x,x_) const sfrl_(x,x_)

    ... the const is inserted in the macro definition. This is resolved by the preprocessor to something like this ...

    #define const_sfrw(x,x_) const extern "C" volatile unsigned int x asm(#x_)

    ... where the const comes before extern "C". As a workaround I removed the four lines above and inserted a complete #ifdef for every const_xxxx with the const after the extern "C":

    #define const_sfrb(x,x_) extern "C" const volatile unsigned char x asm(#x_)
    #define const_sfrw(x,x_) extern "C" const volatile unsigned int x asm(#x_)
    # ...

    This worked for me. I would supply a diff to fix this, but the workaround is ugly (much duplicated code) and I'm pretty unfamiliar with what's exactly going on in these macros. So maybe some insider can have a look at this and fix it?

    Thanks

    Christoph

  • I described my fix here;

    http://forum.43oh.com/topic/5419-code-composer-studio-v6-now-officially-released/?p=47449

  • Christoph, your workaround is no workaround and it isn’t ugly, it simply is the way it has to be done. And it doesn’t generate any excess code. It is even a few microseconds faster when the precompiler parses the defines. :)

     Rick, I don’t know what your ‘fix’ shall be good for: you just deactivate the usage of the extern ”C” switch, so if the header file is included by a C file, the compiler will assume a different name for the register name than if compiled within a C++ file.
    Well, in case of the sfrs, where the address is given explicitly and the compiler won’t generate relocatable references anyway (and the register never needs to be linked), this may work, but it won’t work for functions, not for library constants etc. And it won’t work for CCS and IAR, where the SFRs are linked by the linker and the compiler has to generate relocation entries that have to be resolved by the linker based on the (C) names that are stored in the linker script. Which is the way to go, as it allows generic header files instead of separate ones for each processor due to different register addresses.

     The reason for the existence of the extern “C” is that the C++ compiler renames each element, by adding its namespace and (in case of functions) the parameter types. This is required so different namespaces can have functions with same name, and multiple functions with different parameters can co-exist for operator overloading etc.
    The extern “C makes the element a unique element that is available in all namespaces, just like a C compiler would generate and expect, as C doesn’t support namespaces or operator overloading.

  • Here is a simple .cpp file. When I try to compile with msp430-elf-g++ it falls down pretty quickly. Does this compile successfully for you Jens-Michael Gross?

    // blinkled.cpp - simple c++ led blink
    
    #include <msp430.h>
    
    int main(void) {
      WDTCTL = WDTPW|WDTHOLD;
    
      P1DIR |= (BIT0|BIT6);
      P1OUT &= ~BIT0;
      P1OUT |= BIT6;
      for(;;){
        P1OUT ^= (BIT0|BIT6);
        __delay_cycles(250000); // delay
      }
    
      return 0;
    }
    
    $ msp430-elf-g++ blinkled.cpp -c -mmcu=msp430g2231
    In file included from /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430g2231.h:58:0,
                     from /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430.h:1273,
                     from blinkled.cpp:3:
    /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430g2231.h:409:1: error: expected unqualified-id before string constant
     const_sfrb(P1IN, P1IN_);
     ^
    /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430g2231.h:426:1: error: expected unqualified-id before string constant
     const_sfrb(P2IN, P2IN_);
     ^
    /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430g2231.h:448:1: error: expected unqualified-id before string constant
     const_sfrw(TAIV, TAIV_);
     ^
    /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430g2231.h:692:1: error: expected unqualified-id before string constant
     const_sfrb(CALDCO_1MHZ, CALDCO_1MHZ_);
     ^
    /home/kimballr/Msp430GCCopensource/msp430-elf/include/msp430g2231.h:694:1: error: expected unqualified-id before string constant
     const_sfrb(CALBC1_1MHZ, CALBC1_1MHZ_);
     ^
    

  • Jens-Michael Gross said:

    Rick, I don’t know what your ‘fix’ shall be good for: you just deactivate the usage of the extern ”C” switch, so if the header file is included by a C file, the compiler will assume a different name for the register name than if compiled within a C++ file.

    My quick hack works because when a c++ file includes iomacros.h via a device header such as "msp430.h" which then includes the "msp430g2553.h", that header wraps an extern "C" around everything including the iomacros.h header. So there is no need to explicitly do it in the iomacros.h file.

    ...
    
    #ifndef __MSP430G2553
    #define __MSP430G2553
    
    #define __MSP430_HEADER_VERSION__ 1131
    
    #define __MSP430_TI_HEADERS__
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #include <iomacros.h>
    
    ....
    /************************************************************ * End of Modules ************************************************************/ #ifdef __cplusplus } #endif /* extern "C" */ #endif /* #ifndef __MSP430G2553 */

  • Actually it does. Even though I don’t know why one should use a cpp file when it contains plain C code.
    But I’m using a different toolchain than you and different header files.
    But try the following:

    With your modified header files, put some code in a .c file and some in a .cpp file and try to link them into one binary. Since the cpp file uses name mangling and the c file doesn’t, same registers/functions form the headers get different names.
    Especially with the new way of resolving the register addresses in the linker script, the linker script won’t hold the mangled names that appear if you remove the extern “C” frame from the headers.
    It’s not enough to make things compile, they also need to link afterwards. Which may only coincidentally work in your case.

    So I don’t call it a fix, but rather a kludge, as it only suppresses the symptom, and does not cure the cause.

  • I'm going to stop talking about this as you obviously don't understand that this is a problem specific to iomacros.h that is shipping with the latest msp430-elf-gcc, not some arbitrary msp430-gcc compiler.

    I submitted a post on the compiler forum. They have given me a bugzilla # and they understand the problem.

    http://e2e.ti.com/support/development_tools/compiler/f/343/t/356902.aspx .. the other thread.

    -rick

  • I completely do understand. And I never denied that there is a problem. However, your solution fixes the problem on the wrong end.

    Sure you are right, the iomacros.h is included inside an extern "C" block, so extern "C" isn't required in iomacros.h. However, this is a breach of conventions. One shall not include a file inside an extern "C" block. If the declaration is needed, the included file should do it by itself. Else things like this will happen. It's also possible that a header file requires parts of it NOT being in an extern "C" block.
    Also, an extern "C" shouldn't be part of a macro definition for the same reason: it may cause problems (like the one with the const).

    If breaking with conventions, this must be done for a good reason, and with care (which obviously was missing here).

**Attention** This is a public forum