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.

Using GCC C++ cannot resolve ambiguity between fixed with uint and unsigned.

I get the following error:

/home/sporty/HydroGuardFW/hw_1_5/miwt_os/sensor/transient_sensor.h|148 col 32| error: call of overloaded 'push_str(unsigned int)' is ambiguous
||          out.push_str(data.len());
||                                 ^
/home/sporty/HydroGuardFW/hw_1_5/miwt_os/dispatcher/array_safe.h|816 col 6| note: candidate: bool Array_s<T>::push_str(char) [with T = char]
||  bool Array_s<char>::push_str(char x);
||       ^
/home/sporty/HydroGuardFW/hw_1_5/miwt_os/dispatcher/array_safe.h|822 col 6| note: candidate: bool Array_s<T>::push_str(uint8_t) [with T = char; uint8_t = unsigned char]
||  bool Array_s<char>::push_str(uint8_t x);
||       ^
/home/sporty/HydroGuardFW/hw_1_5/miwt_os/dispatcher/array_safe.h|828 col 6| note: candidate: bool Array_s<T>::push_str(uint16_t) [with T = char; uint16_t = short unsigned int]
||  bool Array_s<char>::push_str(uint16_t x);
||       ^
/home/sporty/HydroGuardFW/hw_1_5/miwt_os/dispatcher/array_safe.h|834 col 6| note: candidate: bool Array_s<T>::push_str(uint32_t) [with T = char; uint32_t = long unsigned int]
||  bool Array_s<char>::push_str(uint32_t x);
||       ^
|| /home/sporty/HydroGuardFW/hw_1_5/miwt_os/dispatcher/array_safe.h: In instantiation of 'bool Array_s<T>::print(SerialTXInterface*) [with T = unsigned int]':

The TI C/C++ compiler as well as the Linux GCC compiler does not generate the same error, this is probably an issue with the stdint.h for the GCC compiler.  Is there a a recommended workaround?

  • A temporary way to fix the issue is to edit the following file:

    ti/ccsv6/tools/compiler/gcc_msp430_5.3.0.219/msp430-elf/include/stdint.h

    /*
     * Copyright (c) 2004, 2005 by
     * Ralf Corsepius, Ulm/Germany. All rights reserved.
     *
     * Permission to use, copy, modify, and distribute this software
     * is freely granted, provided that this notice is preserved.
     */
    
    #ifndef _STDINT_H
    #define _STDINT_H
    
    #include <machine/_default_types.h>
    #include <sys/_intsup.h>
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #ifdef ___int8_t_defined
    typedef __int8_t int8_t ;
    typedef __uint8_t uint8_t ;
    #define __int8_t_defined 1
    #endif
    
    #ifdef ___int_least8_t_defined
    typedef __int_least8_t int_least8_t;
    typedef __uint_least8_t uint_least8_t;
    #define __int_least8_t_defined 1
    #endif
    
    #ifdef ___int16_t_defined
    typedef __int16_t int16_t ;
    // typedef __uint16_t uint16_t ;  // <== Comment out this
    typedef unsigned int uint16_t ;  // <== Add this
    #define __int16_t_defined 1
    #endif

  • Hello,

    We are looking into the matter and trying to get your request to the right team. We will get back to you in time.

    Thanks,

    David
  • Please do, otherwise the library does not work with C++, since it uses parameter types to disambiguate function calls.

  • Hello,

    Your post has been moved to the TI C/C++ Compiler - Forum as I believe they should be able to provide you with the help that you need.

      Thanks,

       David

  • Another workaround would be to cast the value of data.len() to uint16_t before passing it to push_str
  • That makes code not so portable. I want the unsigned to be uint32_t on the 32 bit ARM based system and uint16_t on the msp430.
  • I want to reproduce this problem, then file a bug report with the MSP430 GCC team.  Please preprocess the source file with the problem, and attach that to your next post.  A command like this will do ...

    %> msp430-elf-gcc <-I and -D options here> -E file.c -o file.pp.txt
    

    I use the .txt extension because I know the forum accepts it.  Also indicate the compiler version, and show all the build options exactly as the compiler sees them.

    Thanks and regards,

    -George

  • #include <msp430.h> 
    #include <stdint.h>
    void foo(uint8_t a) { uint32_t k = a; }
    
    void foo(uint16_t a) { uint32_t k = a; }
    
    void foo(uint32_t a) { uint32_t k = a; }
    
    /*
     * main.c
     */
    int main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
        long k = 1;
            foo(k);
            while (1) {
            }
    	return 0;
    }

    Here is the error:

    ~/HydroGuardFW/ws_ccs/temp/Debug$ /home/sporty/ti/ccsv6/utils/bin/gmake -k all
    Building file: ../main.cpp
    Invoking: GNU Compiler
    "/home/sporty/ti/ccsv6/tools/compiler/gcc_msp430_5.3.0.219/bin/msp430-elf-gcc" -c -mmcu=msp430f5335 -I"/home/sporty/ti/ccsv6/ccs_base/msp430/include_gcc" -I"/home/sporty/ti/ccsv6/tools/compiler/gcc_msp430_5.3.0.219/msp430-elf/include" -Os -g -gdwarf-3 -gstrict-dwarf -Wall -mlarge -mhwmult=f5series -mcode-region=none -mdata-region=none -MMD -MP -MF"main.d" -MT"main.o" -o"main.o"  "../main.cpp"
    ../main.cpp: In function 'void foo(uint8_t)':
    ../main.cpp:3:32: warning: unused variable 'k' [-Wunused-variable]
     void foo(uint8_t a) { uint32_t k = a; }
                                    ^
    ../main.cpp: In function 'void foo(uint16_t)':
    ../main.cpp:5:33: warning: unused variable 'k' [-Wunused-variable]
     void foo(uint16_t a) { uint32_t k = a; }
                                     ^
    ../main.cpp: In function 'void foo(uint32_t)':
    ../main.cpp:7:33: warning: unused variable 'k' [-Wunused-variable]
     void foo(uint32_t a) { uint32_t k = a; }
                                     ^
    ../main.cpp: In function 'int main()':
    ../main.cpp:15:14: error: call of overloaded 'foo(long int&)' is ambiguous
             foo(k);
                  ^
    ../main.cpp:3:6: note: candidate: void foo(uint8_t)
     void foo(uint8_t a) { uint32_t k = a; }
          ^
    ../main.cpp:5:6: note: candidate: void foo(uint16_t)
     void foo(uint16_t a) { uint32_t k = a; }
          ^
    ../main.cpp:7:6: note: candidate: void foo(uint32_t)
     void foo(uint32_t a) { uint32_t k = a; }
          ^
    subdir_rules.mk:7: recipe for target 'main.o' failed
    gmake: *** [main.o] Error 1
    gmake: Target 'all' not remade because of errors.
    

    Here is the file:

  • Unfortunately, this test case is flawed.  The compiler legitimately issues the diagnostic about the ambiguous call to foo.  Type long is not a match for any of the types accepted by foo.  You can convert from long to any of those types in one conversion.  Thus it is ambiguous which foo should be called.

    Thanks and regards,

    -George

  • George,

    OK, so I was in the hurray to write the example,

    Line #14 should be

    unsigned long k = 1;

    It should execute:

    void foo(uint32_t a);
  • In your original example, it seems like you're complaining that uint32_t is typedefed as "unsigned long int" instead of "unsigned int"? If so, that's not a bug. If it exists, uint32_t is guaranteed to be an unsigned integer type which is exactly 32 bits wide. There is no guarantee as to which type it will actually be. I think it could even be a non-standard type.

  • Markus,

    First of all, I am not complaining, I am stating a fact, second, where did you get that from?  I am just saying that the compiler cannot disambiguate a method, because there is a bug in TI GCC stdin.h, but they do have it correct in TI C/C++ compiler.

    The correct TI C/C++ stdin.h typedefs:

    /* 7.18.1.1 Exact-width integer types */
    
        typedef   signed char    int8_t;
        typedef unsigned char   uint8_t;
        typedef          int    int16_t;
        typedef unsigned int   uint16_t;
        typedef          long   int32_t;
        typedef unsigned long  uint32_t;

    The wrong GCC typedefs

    #ifdef ___int8_t_defined
    typedef __int8_t int8_t ;
    typedef __uint8_t uint8_t ;
    #define __int8_t_defined 1
    #endif
    
    #ifdef ___int16_t_defined
    typedef __int16_t int16_t ;
    typedef __uint16_t uint16_t ;
    #define __int16_t_defined 1
    #endif
    
    #ifdef ___int32_t_defined
    typedef __int32_t int32_t ;
    typedef __uint32_t uint32_t ;
    #define __int32_t_defined 1
    #endif
    
    

  • By the way, when I replace these fixed width typedefs in GCC library and it works fine. But this is not a correct solution, the library has to be right.
  • Silver Diamond said:
    First of all, I am not complaining, I am stating a fact

    I'm sure Markus meant no negative implication with the word "complaining."  In customer support circles, the word "complains" is pretty much jargon for "reports a bug or deficiency."

  • Archaeologist,

    I understand, and don't care too much, I just want your help to get the tool-chain fixed...
  • Sorry if my choice of words was poor, in no way was "complaining" meant to imply "whining".

    Now as for your problem: there seem to be push_str overloads for uint8_t, uint16_t and uint32_t. The typedefs for these are unsigned char, unsigned short, and unsigned long. The type unsigned int is not in that list. The call is ambiguous because there is no exact match, there is no match for which an integral promotion can be applied (promotions stop at unsigned int), whereas there are three functions for which an integral conversion would be required.

    I don't see anything in the C standard that would forbid GCC's choice of fixed-width types. The only requirement is that they be precisely 8, 16, and 32 bits wide, which unsigned char, unsigned short, and unsigned long are, as far as I can see. I think the only fix is to explicitly cast data.len() to either uint16_t or uint32_t.

  • Markus,

    No worries, as far as the issue ahead, before we go any farther, are you thinking C99 or C++03 standard?

  • C99. I don't think C++03 officially mentions stdint.h, but most implementations I've seen provide a <stdint.h> header, some even <cstdint> (with the same semantics as in C99)

  • Markus,

    OK, now that we are on the same page, that code is not valid C99 code, and yes it is C++03. I worked with C++ for a long time and never seen a toolchain that does provide a library that does not disambiguate between types, TI Optimizing C/C++ tool-chain works, ARM GCC C/C++ works, X86 GCC C/C++ and clang C/C++ works, TI GCC MSP does not work.
  • This may be a quality of implementation issue. However, in a Windows setup, you'd run into the same problems if you tried to push_str an unsigned long. In fact, I just tried to compile

    #include <stdafx.h>
    #include <stdint.h>
    
    void f(char x) {}
    void f(uint8_t x) {}
    void f(uint16_t x) {}
    void f(uint32_t x) {}
    
    int main()
    {
    	unsigned long x = 1;
    	f(x);
    }

    in Visual Studio Express 2010, and sure enough I got

    1>tmp.cpp(12): error C2668: 'f' : ambiguous call to overloaded function
    1>          tmp.cpp(7): could be 'void f(uint32_t)'
    1>          tmp.cpp(6): or       'void f(uint16_t)'
    1>          tmp.cpp(5): or       'void f(uint8_t)'
    1>          tmp.cpp(4): or       'void f(char)'
    1>          while trying to match the argument list '(unsigned long)'
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    

    intN_t does not mean "any" integer N bits wide, but rather "some" integer N bits wide. That's just the way C and C++ work.

  • Markus,

    Please post sizeof(unsigned long);
  • On Windows, sizeof(int) == sizeof(long) (== 4).

    See e.g. here: