Macro for use in expression while enforcing its arguments to be compile time constants

試著忘記壹切 提交于 2019-12-23 01:44:11

问题


I am looking for a way to #define a macro that enforces its arguments to be compile time constants, and at the same time can be used in an expression. The method should be working under C90 and be upward compatible - if possible also portable for the different C++ variants. Also a 0-footprint to memory is preferable.

Consider a compile-time minimum macro as an example. The behavior should be:

 #define CT_MIN(CTC_A, CTC B) <<<MAGIC>>>

 int a = 1;
 int b = a + CT_MIN(1,4); /* OK */
 int c = a + CT_MIN(a,4); /* COMPILER DIAGNOSTIC */

To provoke an compile diagnostic, in general I could emulate a static assert with something like:

 typedef char ct_check_is_ct_constant[(CTC_A != 0) + 1];

which wouldn't compile (or will raise some diagnostic at least) if anything other than a compile time constant (number) is used for CTC_A; but if CTC_A is an number, it will always be successful (given some care with scopes). But this assert would only work within a multi-statement macro and so would not be possible to use as part of an expression.

I would guess, something in the lines of:

  #define CT_MIN(CTC_A, CTC_B)                   \
         ( <expr check CTC_A>,                   \
           <expr check CTC_B>,                   \
           (CTC_A) < (CTC_B))? (CTC_A) : (CTC_B) \
         )

But I have no idea how the expressions must look like, and if such thing exists.

Any Ideas?

Background:

I have a huge amount of constants from not too much reliable sources via an costumized header. These constants strongly parametrize my code. I want to implement a zero footprint checks during preprocessor and compile time for this constants, to check both my assumptions, the environment, and my skills to write a correct code generator.


回答1:


You can use sizeof applied to an anonymous struct with a single field whose type is a locally defined enum whose values must be constant integer expressions:

#define CT_MIN(CTC_A, CTC_B)                                               \
    ( sizeof(struct { enum { must_be_constant_expression = CTC_A } x; }),  \
      sizeof(struct { enum { must_be_constant_expression = CTC_B } x; }),  \
      (CTC_A) < (CTC_B) ? (CTC_A) : (CTC_B)                                )

The error messages produced by clang is very explicit:

enumassert.c:32:24: error: expression is not an integer constant expression
    int c = a + CT_MIN(a,4); /* COMPILER DIAGNOSTIC */
                       ^
enumassert.c:17:60: note: expanded from macro 'CT_MIN'
    ( sizeof(struct { enum { must_be_constant_expression = CTC_A } x; }),  \
                                                           ^

This solution does not seem to add any symbol to the name space. Furthermore, if you need to handle non integer types, at the cost of a slightly less precise error message, you can add a cast like this:

#define CT_MIN(CTC_A, CTC_B)                                               \
    ( sizeof(struct { enum { must_be_constant_expression = (int)(CTC_A) } x; }),  \
      sizeof(struct { enum { must_be_constant_expression = (int)(CTC_B) } x; }),  \
      (CTC_A) < (CTC_B) ? (CTC_A) : (CTC_B)                                )



回答2:


For evaluation of both floating point and integer compile-time constants I think I can use @chqrlie's solution and upgrade it a little.

The expression for the check if the parameter is a compile time constant might be:

  sizeof(struct { enum { must_be_constant_expression = (int) (!(CTC_A))} x; })

(I am not sure if the unary ! gives yield an int or something of type of CTC_A)

This should handle most of anything, that a MIN operation can be reasonably done for at compile time.

The complete macro then is:

 #define CT_MIN(CTC_A, CTC_B)                                                         \
     ( sizeof(struct { enum { must_be_constant_expression = (int) (!(CTC_A)) } x; }), \
       sizeof(struct { enum { must_be_constant_expression = (int) (!(CTC_B)) } x; }), \
       (CTC_A) < (CTC_B) ? (CTC_A) : (CTC_B)                                          \
     )


来源:https://stackoverflow.com/questions/35107413/macro-for-use-in-expression-while-enforcing-its-arguments-to-be-compile-time-con

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!