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.

MSP430-GCC-OPENSOURCE: uint16_t is short unsigned int

Part Number: MSP430-GCC-OPENSOURCE

I see that the uint16_t/int16_t types are aliases for the short unsigned int/short int types. Is there a reason for why the "short" keyword exists in this typedef on MSP430? My linter is throwing a fit when assigning the address of 16-bit registers (which are external variables declared as unsigned int) to pointers of type uint16_t *.

  • Hi Thil,

    A lot of the folks originally involved in these type definitions are no longer here - so it would be difficult for me to give you the rationale for this decision.  I'll consult with my colleagues to see if I can find an answer for you.

    BR,
    Leo

  • Hi Thilo,

    According to C, int and unsigned int don't really have a defined size but it depends on the compiler or platform. In MSP430, it's typically 16-bits (since it's a 16-bit architecture) but in other architectures it could be 32-bits.

    On the other hand, short is for 16-bits, which is why it makes sense to use it for uint16_t/int16_t.

    I understand that doesn't help you much with your error, but you should be able to fix it with casting. I believe you should be getting a warning and not an error, correct?

  • I've never seen the term linter.  But I presume it is a static code analysis tool similar to lint.

    It appears to me the problem is that the linter makes the presumption (at least in some cases) short cannot be equivalent to int.  However, that is precisely the case on the MSP430.  While this is unusual, it is not a violation of the standards for the C programming language.  I suggest you try to configure this linter so short and int are equivalent.

    Thanks and regards,

    -George

  • > I've never seen the term linter.  But I presume it is a static code analysis tool similar to lint.

    You assume correctly, it is a somewhat colloquial noun for a static code analyser (in my case pclint plus).

    I am fully aware, that on the MSP430, short int and int have the same width. However, I have rechecked this behaviour. It turns out that it is not only the linter that complains. It is GCC also.

    This code snippet:

    volatile uint16_t *regPtr = &UCA0CTLW0;

    which should be perfectly valid code, results in this GCC warning:

    warning: initialization of 'volatile uint16_t *' {aka 'volatile short unsigned int *'} from incompatible pointer type 'volatile unsigned int *' [-Wincompatible-pointer-types]

    so even GCC prints a warning.

    pclint plus says:

    warning 2454: incompatible pointer types initializing 'volatile uint16_t *' (aka 'volatile unsigned short *') with an expression of type 'volatile unsigned int *' [MISRA 2012 Rule 1.3, required]

    These warnings simply stem from inconsistency between how the sfr_w() macro and how uint16_t is defined.

    By Luis:

    > On the other hand, short is for 16-bits, which is why it makes sense to use it for uint16_t/int16_t.

    It may be so on x86 (and some other platforms), but I am not aware that this fixed width is mandated by C89 or C99. These only specify minimum widths for these types.

     but you should be able to fix it with casting

    Yes, at present I am casting around this, currently, as I have no other choice. This is not ideal though, as it will also remove legitimate warnings (for instance, when casting to a 32-bit pointer)

    > I believe you should be getting a warning and not an error, correct?

    Correct, it is a warning.

    From my point of view, there are three possibilities to fix this:

    - typedef unsigned int uint16_t;

    or

    - #define sfr_w(x) extern volatile unsigned short int x

    or

    - Change MSP430-GCC to not emit these warnings for short int <-> int pointer conversions and accept that this solution will still trip up a good number of static code analysers.

  • Hi Thilo,

    Thanks for this feedback. I'll pass this suggestion on to the relevant folks here.

    BR,

    Leo

  • I agree, those are all valid fixes, although the 1st one will cause your uint16_t to be 32-bits if ported to other platforms/compilers.

    IMO, a casting 

    volatile uint16_t *regPtr = (uint16_t *) &UCA0CTLW0;

    is completely valid since you know this register is 16-bit and you are telling the compiler that you want to access it as 16-bits. 

    I understand that you wouldn't want to do this for a 32-bit register, but at the same time, you wouldn't assign it to a uint16_t, but to a uint32_t. If you do assign it to a uint16_t, you should just get half the register anyways with or without casting. 

    Or maybe I'm not understanding what you say about legitimate warnings.

    Regards,

    Luis R

  • > I agree, those are all valid fixes, although the 1st one will cause your uint16_t to be 32-bits if ported to other platforms/compilers

    I was under the assumption, that the whole point of the uint*_t C99 types is that platform/compiler toolchains provide these typedefs inside their system/compiler toolchain headers. So when one ports code to say x86, system headers just do the right thingTm and define uint16_t to unsigned short int. I doubt the system-specific MSP430 system headers would be included on other platforms.

    > IMO, a casting volatile uint16_t *regPtr = (uint16_t *) &UCA0CTLW0; is completely valid since you know this register is 16-bit and you are telling the compiler that you want to access it as 16-bits.

    This was just a code snippet to trigger the warning for you. In my software, this assignment from hardware register symbols (which fundamentally come from linker scripts in the MSP430-GCC toolchain) goes through a layer of C macros, where what happens is not immediately obvious to the user. And indeed, a cast like this is a part of these macros. I have successfully worked around all these issues in my code some time ago, but this solution came with drawbacks that I don't remember off the top off my head. I think there were some other issues, e.g. when dereferencing the pointer and using other types that arise naturally when using some libraries. Also, when using these macros, some warnings from GCC (or the linter), that are perfectly valid, are now muted due to the cast.

    The point is, there is this inconsistency in the MSP430-GCC toolchain, and making the compiler and pclint+ happy at the same time was quite painful for me because of this inconsistency. I am merely reporting the inconsistency that I found, and you can make of this information what you will.

  • Ah, that makes sense.

    Thanks for the clarification and the feedback.

  • One more suggestion I got from a peer:

    #define sfr_w(x) extern volatile uint16_t x

    Not a bad option, don't you think?

  • I'm afraid this is not possible. uint16_t is C99 and would require all users to include stdint.h before these types become visible. Besides, as these are used exclusively in MSP-specific system headers, we do not require types with guaranteed width in the same way as portable code does.

    In my opinion, the best and least painful option still is to typedef unsigned int uint16_t. "int" usually (but not always) maps to a machine's fundamental register size.

    But really, the types from sfr_w and uint16_t ought to be consistent.

  • Thanks Thilo,

    We'll discuss with the team.

    BR,

    Leo

**Attention** This is a public forum