Remove cast from constant in preprocessor

前端 未结 5 1885
醉酒成梦
醉酒成梦 2021-01-12 18:48

Background

In a microcontroller code, I am using a library provided by the producer where there are many constants defined. I\'m trying to give an error if there\'

相关标签:
5条回答
  • 2021-01-12 18:57

    I know the issue thread is old, however I encountered it today... If you do not want to or cannot change the #define, the other answers are great, but if you have access to the #define, I recommend using for pre-processor operations (#if - #else - #endif) instead of:

    #define FLASH_BLOCK_SIZE ((uint8_t)64)
    

    use this define:

    #define FLASH_BLOCK_SIZE (64U)
    

    This way the cast is still there, and the compiler won't be "confused".

    0 讨论(0)
  • 2021-01-12 19:01

    After macro replacement, a preprocessor expression may have subexpressions of the form defined identifier or defined ( identifier ). Other than that, identifiers and keywords have no meaning; each identifier or keyword is replaced by 0. So this:

    #if 64 != ((uint8_t)64)
    

    is equivalent to this:

    #if 64 != ((0)64)
    

    which is a syntax error. The fact that it's a typedef isn't the problem; a keyword like int gets the same treatment.

    So given:

    #define FLASH_BLOCK_SIZE ((uint8_t)64)
    

    you can't use FLASH_BLOCK_SIZE in a preprocessor expression.

    The best solution I can think of is to change your definition:

    #define FLASH_BLOCK_SIZE_NUM 64
    #define FLASH_BLOCK_SIZE ((uint8_t)FLASH_BLOCK_SIZE_NUM)
    

    You can then use FLASH_BLOCK_SIZE_NUM in preprocessor expressions and FLASH_BLOCK_SIZE elsewhere.

    On the other hand, do you really need the (int8_t) cast in the first place? Arithmetic expressions are implicitly converted in many contexts, usually to the appropriate type. In many contexts, (uint8_t) will be promoted to int anyway. It's very likely you can just drop the cast and use:

    #define FLASH_BLOCK_SIZE 64
    

    To be sure, you'll need to examine all the code that refers to FLASH_BLOCK_SIZE. (Evaluating sizeof FLASH_BLOCK_SIZE would be a problem, but I'm betting you never do that.)

    0 讨论(0)
  • 2021-01-12 19:07

    Here is an improved version (the first version is below). This one does not depend on the cast being uint8_t; it will work with any FLASH_BLOCK_SIZE replacement list of the form ((some type) number).

    #define MYPROG_BLOCK_SIZE   64
    #define FLASH_BLOCK_SIZE    ((uint8_t)64)
    
    #define B(x)
    #define C(x)    B x
    #define D(x)    C x
    
    #if MYPROG_BLOCK_SIZE != D(FLASH_BLOCK_SIZE)
        #error "mismatch between actual block size and defined block size"
    #endif
    

    Here is the original version:

    #define MYPROG_BLOCK_SIZE  64
    #define FLASH_BLOCK_SIZE   ((uint8_t)64)
    
    #define uint8_t             
    #define Helper(x)          x
    #define Deparenthesize(x)  Helper x
    
    #if MYPROG_BLOCK_SIZE != Deparenthesize(Deparenthesize(FLASH_BLOCK_SIZE))
        #error "mismatch between actual block size and defined block size"
    #endif
    #undef uint8_t
    

    When writing code, I would prefer a static assert, but the above does what you requested in the preprocessor.

    0 讨论(0)
  • 2021-01-12 19:09

    For any typedef you can get arrount this by changing to

    #define FLASH_BLOCK_SIZE ((uint8_t)+64)
    

    notice the little plus in there?

    The preprocessor replaces the typename it doesn't know anything about by 0, so this works out in both contexts. (The preprocessor is supposed to do all arithmetic in [u]intmax_t, anyhow)

    For the actual type you are using all of this makes not much sense. There is no such thing as a uint8_t constant. As soon they are evaluated all expressions of a type that is narrower than int are converted to int. So it probably doesn't makes any difference.

    0 讨论(0)
  • 2021-01-12 19:14

    The solution is to use static assert. With a good STATIC_ASSERT macro, you can put a static assert at file-scope in your header file:

    STATIC_ASSERT(FLASH_BLOCK_SIZE == MYPROG_BLOCK_SIZE);
    

    Here is an exemple of definition for the STATIC_ASSERT macro:

    #define CAT(x, y) CAT_(x, y)
    #define CAT_(x, y) x ## y
    
    #define STATIC_ASSERT(expr)  \
        extern int CAT(static_assert_failed_, __LINE__)[(expr) ? 1 : -1]
    

    With some compilers (e.g., IAR), you have static_assert as a compiler builtin. static_assert is also present in C11 but unfortunately not a lot of embeffffded C compiler support C11.

    0 讨论(0)
提交回复
热议问题