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.

Compiler/ARM-CGT: Variadic Macro leads to error when comipling with --strict_ansi

Part Number: ARM-CGT

Tool/software: TI C/C++ Compiler

I am compiling with --c99 and using a variadic macro which works fine and as expected (tested on the actual hardware countless times).

However, the goal is to compile with  --c99 and --strict_ansi. But now I am getting the error on the variadic macro usage:

error #55-D: too few arguments in invocation of macro "GET_MACRO"

ISO C99 introduces variadic macros so why do I get this error? This variadic macro is used so often that local supressions are not an option and globally supressing warnings is almost never a good advice.

So how to solve this issue?

  • Unfortunately, I am unable to reproduce the issue.

    I cannot ask for the typical preprocessed test case, because your problem occurs during preprocessing.  So, I'd appreciate if you would cut the problem down to a smaller size.  Keep in mind I only need to compile one file.  I don't need to link or run.  Please put the file(s) into a zip file, then attach that to your next post.

    Please show all the build options exactly as the compiler sees them.  Copy-n-paste them into your next post.

    What version of the compiler do you use?

    Thanks and regards,

    -George

  • Consider the following Code:

    #define GET_MACRO(_1, _2, _3, NAME, ...) NAME
    #define FOO(...) GET_MACRO(__VA_ARGS__, foo3, foo2, foo1)(__VA_ARGS__)
    
    int foo1 (int i) {
        return i;
    }
    
    int foo2 (int i, int j) {
        return i + j;
    }
    
    int foo3 (int i, int j, int k) {
        return i + j + k;
    }
    
    
    int main(void)
    {
        int var = 0;
        var = FOO(1);
        var += FOO(1, 2);
        var += FOO(1, 2, 3);
        var++;
        return 0;
    }

    This compiles fine in c99 mode:

    **** Build of configuration Debug for project variadic_macro ****
    
    "C:\\ti\\ccs1000\\ccs\\utils\\bin\\gmake" -k -j 8 all -O 
     
    Building file: "../main.c"
    Invoking: ARM Compiler
    "C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/bin/armcl" -mv7R5 --code_state=32 --float_support=VFPv3D16 --include_path="D:/test/ti-hercules-crc-examples/src/CCS_Projects/variadic_macro" --include_path="C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/include" -g --c99 --diag_warning=225 --diag_wrap=off --display_error_number --enum_type=packed --abi=eabi --preproc_with_compile --preproc_dependency="main.d_raw"  "../main.c"
    Finished building: "../main.c"
     
    Building target: "variadic_macro.out"
    Invoking: ARM Linker
    "C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/bin/armcl" -mv7R5 --code_state=32 --float_support=VFPv3D16 -g --c99 --diag_warning=225 --diag_wrap=off --display_error_number --enum_type=packed --abi=eabi -z -m"variadic_macro.map" --heap_size=0x800 --stack_size=0x800 -i"C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/lib" -i"C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/include" --reread_libs --diag_wrap=off --display_error_number --warn_sections --xml_link_info="variadic_macro_linkInfo.xml" --rom_model --be32 -o "variadic_macro.out" "./main.obj"  -llibc.a 
    <Linking>
    warning #10247-D: creating output section ".text" without a SECTIONS specification
    Finished building target: "variadic_macro.out"
     
    
    **** Build Finished ****

    Now adding --strict_ansi:

    **** Build of configuration Debug for project variadic_macro ****
    
    "C:\\ti\\ccs1000\\ccs\\utils\\bin\\gmake" -k -j 8 all -O 
     
    Building file: "../main.c"
    Invoking: ARM Compiler
    "C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/bin/armcl" -mv7R5 --code_state=32 --float_support=VFPv3D16 --include_path="D:/test/ti-hercules-crc-examples/src/CCS_Projects/variadic_macro" --include_path="C:/ti/ccs1000/ccs/tools/compiler/ti-cgt-arm_20.2.0.LTS/include" -g --c99 --diag_warning=225 --diag_wrap=off --display_error_number --enum_type=packed --abi=eabi --preproc_with_compile --preproc_dependency="main.d_raw"  --strict_ansi "../main.c"
     
    >> Compilation failure
    subdir_rules.mk:9: recipe for target 'main.obj' failed
    "../main.c", line 20: error #55-D: too few arguments in invocation of macro "GET_MACRO"
    1 error detected in the compilation of "../main.c".
    gmake: *** [main.obj] Error 1
    gmake: Target 'all' not remade because of errors.
    
    **** Build Finished ****

  • The C99 ANSI standard, in section 6.10.3, says in regards to an invocation of a macro that accepts a variable number of arguments ...

    there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...).

    The macro invocation FOO(1) is replaced with ...

    GET_MACRO(1, foo3, foo2, foo1)(1)

    That's 4 arguments.  To avoid violating the above sentence from the standard, there should be 5 or more.  Thus, the diagnostic.

    I understand why you hesitate to suppress compiler diagnostics.  But I think that is the best way forward.  In your first post, the text for this diagnostic includes #55-D.  This means the ID number of this diagnostic is 55, and it is discretionary.  Since it is discretionary, it can be suppressed.  There are a few different ways to suppress it  One is to use the build option --diag_suppress=55.  

    BTW, the link above to the C99 ANSI standard is not to the official standard, but the latest publicly available draft.  For most purposes, including this one, it is close enough.

    Thanks and regards,

    -George

  • Thanks George for your excellent explanation. However, I know wonder if this fix is not sufficient:
    The dummy argument is append, and the function is dummy is empty to the compiler should optimize it away and no runtime performance decrease should appear.
    Or is there anything I am missing, why this fix is a bad idea?
    #define GET_MACRO(_1, _2, _3, NAME, ...) NAME
    #define FOO(...) GET_MACRO(__VA_ARGS__, foo3, foo2, foo1, dummy)(__VA_ARGS__)
    void dummy(void){}
    int foo1 (int i) {
        return i;
    }
    int foo2 (int i, int j) {
        return i + j;
    }
    int foo3 (int i, int j, int k) {
        return i + j + k;
    }
    
    int main(void)
    {
        int var = 0;
        var = FOO(1);
        var += FOO(1, 2);
        var += FOO(1, 2, 3);
        var++;
     return 0;
    }

    By that I would not need to supress compiler warnings.

  • user6135372 said:
    is there anything I am missing

    No.  This looks like a reasonable fix.

    user6135372 said:
    function is dummy is empty to the compiler should optimize it away and no runtime performance decrease should appear.

    No calls are generated to the dummy function.  However, it still takes up space in the object file.  You may choose ignore that small amount of wasted space.  If you want be certain the dummy function is removed, then build with the compiler option --gen_func_subsections.  This causes each function to be placed in its own subsection.  Any such subsection which is not referenced is removed by the linker.  Another way to think about it: If a function in its own section is not called, then it is removed.  However, in some cases, using --gen_func_subsections can cause the overall amount of memory usage to go up.  The only way to know for sure is to experiment.

    Thanks and regards,

    -George

  • Understood, thanks again for that perfect answer!