how can I avoid the use of #if in a polymorphic print macro

后端 未结 4 676
终归单人心
终归单人心 2021-01-26 11:41

Let\'s try to run the following code:

#include 
#define MY_MACRO1(isArray,y) do { \\
                      if(isArray) \\
                                 


        
4条回答
  •  不知归路
    2021-01-26 12:48

    Sum up and another works around using VLA & macros.

    Using _Generic

    #include 
    #include 
    #include 
    #include 
    #include 
    
    static inline void printNonArray_u32 (uint32_t obj)
    {
        printf("interger >> uint32_t : %u\n",obj);
    }
    static inline void printNonArray_u16 (uint16_t obj)
    {
        printf("interger >> uint16_t : %u\n",obj);
    }
    static inline void printNonArray_u8 (uint8_t obj)
    {
        printf("interger >> uint8_t : %d\n",obj);
    }
    static inline void printArray_u32 (const uint32_t* obj)
    {
        printf("array >> uint32_t : "); 
        for(uint32_t i = 0 ; i> uint16_t : "); 
        for(uint32_t i = 0 ; i> uint8_t : "); 
        for(uint32_t i = 0 ; i> uint32_t : 257                                             >> OK                                                                                                                                                                                                
        MY_POLYMORPHIC_PRINT2(i2);           //interger >> uint16_t : 257                                             >> OK                                                                                                                                                                              
        MY_POLYMORPHIC_PRINT2(i3);           //interger >> uint8_t : 25                                               >> OK                                                                                                                                                                                                            
        MY_POLYMORPHIC_PRINT2(a1);           //array >> uint32_t : 42 - 43 -                                          >> FAILS                                                                                                                                                                                                 
        MY_POLYMORPHIC_PRINT2(a2);           //array >> uint16_t : 22 - 23 - 24 - 257 -                               >> OK                                                                                                                                                                                    
        MY_POLYMORPHIC_PRINT2(a3);           //array >> uint8_t : 12 - 13 - 14 - 25 - 253 - 127 - 0 - 0 -             >> FAILS                             
    
        return 0;
    }
    

    pros:

    • simple macro + simple functions
    • you don't need C++ library
    • you don't need "isArray" anymore
    • you don't need #if
    • type-safe

    cons:

    • how to get the array size? --> gives some bad results without
    • limited to C11

    Using VLA (no ##)

    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define MY_POLYMORPHIC_PRINT1(y, type) do { \
                          if((sizeof(y)/sizeof(type) != 1) && (sizeof(y)/sizeof(type) != sizeof(y))) \
                          { \
                              type arrayBuffer[sizeof(y)/sizeof(type)]; \
                              memcpy(&arrayBuffer,&y,sizeof(y)); \
                              printf("array >> "#type" : "); \
                              for(uint32_t i = 0 ; i> "#type" : %d\n",intBuffer); \
                          } \
                         }while(0)
    
    int main()
    {
        uint32_t i1 = 257;
        uint16_t i2 = 257;
        uint8_t  i3 = 25;
        uint32_t a1[]={42,43,44,257};
        uint16_t a2[]={22,23,24,257};
        uint8_t  a3[]={12,13,14,25};
    
        printf("MY_POLYMORPHIC_PRINT1 - VLA\n");
        MY_POLYMORPHIC_PRINT1(i1,uint32_t);// integer >> uint32_t : 257                                               >> OK                                                                                                     
        MY_POLYMORPHIC_PRINT1(i2,uint16_t);// integer >> uint16_t : 257                                               >> OK  
        MY_POLYMORPHIC_PRINT1(i3,uint8_t); // integer >> uint8_t : 25                                                 >> OK  
        MY_POLYMORPHIC_PRINT1(i1,uint8_t); // integer >> uint8_t : 1                                                  >> POK  wrong type, casting is working                                                                                        
        MY_POLYMORPHIC_PRINT1(a1,uint32_t);// array >> uint32_t : 42 - 43 - 44 - 257 -                                >> OK
        MY_POLYMORPHIC_PRINT1(a2,uint16_t);// array >> uint16_t : 22 - 23 - 24 - 257 -                                >> OK
        MY_POLYMORPHIC_PRINT1(a3,uint8_t); // integer >> uint8_t : 12                                                 >> FAILS
        MY_POLYMORPHIC_PRINT1(a1,uint16_t); // integer >> uint16_t : 42 - 0 - 43 - 0 - 44 - 0 - 257 - 0 -             >> POK  wrong type, casting is somewhat working
    
        return 0;
    }
    

    pros:

    • flexible
    • compatibility : C99, C11 (VLA option), ...
    • just one (ugly) macro
    • you don't need C++ library
    • you don't need "isArray" anymore
    • you don't need array size as an argument
    • you don't need #if

    cons:

    • not type-safe --> gives some bad results
    • not compatible before C99
    • need type info

    Using VLA + ## (string concatenation macro)

    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define MY_VLA_PRINT_ARRAY(y, type) do{\
                              type arrayBuffer[sizeof(y)/sizeof(type)]; \
                              memcpy(&arrayBuffer,&y,sizeof(y)); \
                              printf("array >> "#type" : "); \
                              for(uint32_t i = 0 ; i> "#type" : %d\n",intBuffer); \
                              }while(0)
    
    #define MY_POLYMORPHIC_PRINT3( y, isArray, type) do { \
                          MY_VLA_PRINT_ ## isArray (y, type); \
                         }while(0)
    
    int main()
    {
        uint32_t i1 = 257;
        uint16_t i2 = 257;
        uint8_t  i3 = 25;
        uint32_t a1[]={42,43,44,257};
        uint16_t a2[]={22,23,24,257};
        uint8_t  a3[]={12,13,14,25};
    
    
        printf("MY_POLYMORPHIC_PRINT3 -  ## + VLA\n");
        MY_POLYMORPHIC_PRINT3(i1,NOT_ARRAY,uint32_t); // integer >> uint32_t : 257                                    >> OK                                                                                                     
        MY_POLYMORPHIC_PRINT3(i2,NOT_ARRAY,uint16_t); // integer >> uint16_t : 257                                    >> OK  
        MY_POLYMORPHIC_PRINT3(i3,NOT_ARRAY,uint8_t);  // integer >> uint8_t : 25                                      >> OK  
        MY_POLYMORPHIC_PRINT3(i1,NOT_ARRAY,uint8_t);  // integer >> uint8_t : 1                                       >> POK  wrong type, casting is working                                                                                        
        MY_POLYMORPHIC_PRINT3(i1,ARRAY,uint8_t);      // array >> uint8_t : 1 - 1 - 0 - 0 -                           >> POK (does not crash)                                                                                       
        MY_POLYMORPHIC_PRINT3(a1,ARRAY,uint32_t);     // array >> uint32_t : 42 - 43 - 44 - 257 -                     >> OK
        MY_POLYMORPHIC_PRINT3(a2,ARRAY,uint16_t);     // array >> uint16_t : 22 - 23 - 24 - 257 -                     >> OK
        MY_POLYMORPHIC_PRINT3(a3,ARRAY,uint8_t);      // array >> uint8_t : 12 - 13 - 14 - 25 -                       >> OK
        MY_POLYMORPHIC_PRINT3(a1,ARRAY,uint16_t);     // array >> uint16_t : 42 - 0 - 43 - 0 - 44 - 0 - 257 - 0 -     >> POK  wrong type, casting is somewhat working
        MY_POLYMORPHIC_PRINT3(a1,NOT_ARRAY,uint16_t); // integer >> uint16_t : 42                                     >> POK (does not crash)
    
        return 0;
    }
    

    pros:

    • only solution that works for all test cases
    • quite simple macros
    • you don't need C++ library
    • you don't need #if

    cons:

    • not compatible before C99
    • need isArray
    • need type info
    • is not type-safe --> but did not give some too bad results

    macro ## without VLA:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define MY_NON_VLA_PRINT_ARRAY_U32(y) do{\
                              printf("array >> uint32_t : "); \
                              for(uint32_t i = 0 ; i< sizeof(y) / sizeof(uint32_t)  ; i++ ) \
                                printf("%d - ",(uint32_t)*((uint32_t*)&y+(uint32_t*)i)); \
                              printf("\n"); \
                              }while(0)
    #define MY_NON_VLA_PRINT_ARRAY_U16(y) do{\
                              printf("array >> uint16_t : "); \
                              for(uint32_t i = 0 ; i< sizeof(y) / sizeof(uint16_t)  ; i++ ) \
                                printf("%d - ",(uint16_t)*((uint16_t*)&y+(uint16_t*)i)); \
                              printf("\n"); \
                              }while(0)
    #define MY_NON_VLA_PRINT_ARRAY_U8(y) do{\
                              printf("array >> uint8_t : "); \
                              for(uint32_t i = 0 ; i< sizeof(y) / sizeof(uint8_t)  ; i++ ) \
                                printf("%d - ",(uint8_t)*((uint8_t*)&y+(uint8_t*)i)); \
                              printf("\n"); \
                              }while(0)
    #define MY_NON_VLA_PRINT_NOT_ARRAY_U32(y) do{\
                              printf("integer >> uint32_t : %d\n",(uint32_t)y); \
                              }while(0)
    #define MY_NON_VLA_PRINT_NOT_ARRAY_U16(y) do{\
                              printf("integer >> uint16_t : %d\n",(uint16_t)y); \
                              }while(0)
    #define MY_NON_VLA_PRINT_NOT_ARRAY_U8(y) do{\
                              printf("integer >> uint8_t : %d\n",(uint8_t)y); \
                              }while(0)
    
    
    #define MY_POLYMORPHIC_PRINT4( y, isArray, type) do { \
                          MY_NON_VLA_PRINT_ ## isArray ## _ ## type (y); \
                         }while(0)
    
    
    int main()
    {
        uint32_t i1 = 257;
        uint16_t i2 = 257;
        uint8_t  i3 = 25;
        uint32_t a1[]={42,43,44,257};
        uint16_t a2[]={22,23,24,257};
        uint8_t  a3[]={12,13,14,25};
    
    
        printf("MY_POLYMORPHIC_PRINT4 -  ## + no VLA\n");
        MY_POLYMORPHIC_PRINT4(i1,NOT_ARRAY,U32);                                                                                         
        MY_POLYMORPHIC_PRINT4(i2,NOT_ARRAY,U16);      
        MY_POLYMORPHIC_PRINT4(i3,NOT_ARRAY,U8);       
        MY_POLYMORPHIC_PRINT4(i1,NOT_ARRAY,U8);                                                                                      
        MY_POLYMORPHIC_PRINT4(i1,ARRAY,U8);                                                                          
        MY_POLYMORPHIC_PRINT4(a1,ARRAY,U32);          
        MY_POLYMORPHIC_PRINT4(a2,ARRAY,U16);          
        MY_POLYMORPHIC_PRINT4(a3,ARRAY,U8);           
        MY_POLYMORPHIC_PRINT4(a1,ARRAY,U16);          
        MY_POLYMORPHIC_PRINT4(a1,NOT_ARRAY,U16);      
    
        //does not compile:
        // error: invalid operands to binary + (have ‘uint32_t * {aka unsigned int *}’ and ‘uint32_t * {aka unsigned int *}’)
        //                        printf("%d - ",(uint32_t)*((uint32_t*)&y+(uint32_t*)i)); \
        // error: invalid operands to binary + (have ‘uint16_t * {aka  short unsigned int *}’ and ‘uint16_t * {aka short unsigned int *}’)
        //                        printf("%d - ",(uint16_t)*((uint16_t*)&y+(uint16_t*)i)); \
        // error: invalid operands to binary + (have ‘uint8_t * {aka unsigned char *}’ and ‘uint8_t * {aka unsigned char *}’)
        //                        printf("%d - ",(uint8_t)*((uint8_t*)&y+(uint8_t*)i)); \
    
        return 0;
    }
    

    pros:

    • would be compatible before C99
    • you don't need C++ library
    • you don't need #if

    cons:

    • does not compile!
    • a lot of macros
    • need isArray
    • need type info
    • is not type-safe

提交回复
热议问题