避免在 _generic 宏中使用 "warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] "

Avoid "warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] " in a _generic macro

以下代码按预期工作,


#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#define GEN__INTEGER_ 0 
#define GEN__STRING_ 1 
#define GEN__U8_ARRAY_ 2
#define GEN__U16_ARRAY_ 3
#define GEN__U32_ARRAY_ 4

#define INTEGER_EQUAL(observed,expected)        (observed == expected)
#define STRING_EQUAL(observed,expected)         (strcmp((char *)observed, (char *)expected) == 0)
#define U8_ARRAY_EQUAL(observed,expected)       (memcmp((uint8_t *)observed, (uint8_t *)expected, sizeof(expected)/sizeof(uint8_t)) == 0)
#define U16_ARRAY_EQUAL(observed,expected)      (memcmp((uint16_t *)observed, (uint16_t *)expected, sizeof(expected)/sizeof(uint16_t)) == 0)
#define U32_ARRAY_EQUAL(observed,expected)      (memcmp((uint32_t *)observed, (uint32_t *)expected, sizeof(expected)/sizeof(uint32_t)) == 0)
#define GENERIC_EQUAL(observed,expected)        do{ \
                                                   printf("Is "#observed" equal to "#expected" ? "); \
                                                   if( _Generic( \
                                                   (observed)+0, \
                                                   default:   INTEGER_EQUAL(observed,expected), \
                                                   char *:    STRING_EQUAL(observed,expected), \
                                                   uint8_t *: U8_ARRAY_EQUAL(observed,expected), \
                                                   uint16_t *: U16_ARRAY_EQUAL(observed,expected), \
                                                   uint32_t *: U32_ARRAY_EQUAL(observed,expected) \
                                                   )) {printf("[OK]\n");} else {printf("[FAILS]\n");}\
                                                }while(0)

#define INTEGER_PRINT(data)     printf("integer : %d\n",data)
#define STRING_PRINT(data)      printf("string : %s\n",data);
#define U8_ARRAY_PRINT(data)    do{ \
                                    uint8_t gen_buf_[sizeof(data)]; \
                                    memcpy(gen_buf_,(uint8_t*)data,sizeof(data)); \
                                    printf("arr_u8 : "); \
                                    for(uint8_t _igen_ = 0; _igen_<sizeof(data)/sizeof(uint8_t);_igen_++) \
                                    {  \
                                       printf("%d,",gen_buf_[_igen_]); \
                                    } \
                                    printf("\n"); \
                                }while(0)

#define GENERIC_PRINT(data)     do{\
                                    switch(_Generic( \
                                            (data)+0, \
                                            default:   GEN__INTEGER_, \
                                            char *:    GEN__STRING_, \
                                            uint8_t *: GEN__U8_ARRAY_, \
                                            uint16_t *: GEN__U16_ARRAY_, \
                                            uint32_t *: GEN__U32_ARRAY_ \
                                          )){  \
                                        case GEN__STRING_: STRING_PRINT(data); break;\
                                        case GEN__U8_ARRAY_: U8_ARRAY_PRINT(data); break;\
                                        case GEN__U16_ARRAY_: U8_ARRAY_PRINT(data); break; \
                                        case GEN__U32_ARRAY_: U8_ARRAY_PRINT(data); break; \
                                        default: INTEGER_PRINT(data); break; \
                                    } \
                                } while(0)

int main()
{
    uint8_t integ1 = 0;
    uint8_t integ2 = 1;
    GENERIC_EQUAL(integ1,integ2);
    GENERIC_PRINT(integ1);

    char string1[]="abc";
    char string2[]="abc";
    GENERIC_EQUAL(string1,string2);
    GENERIC_PRINT(string1);

    uint8_t array0[]={1,2};
    uint8_t array1[]={1,2};
    uint8_t array2[]={1,3};
    uint8_t array3[]={1,2,3,4};
    GENERIC_EQUAL(array1,array0);
    GENERIC_EQUAL(array1,array2);
    GENERIC_EQUAL(array1,array3);
    GENERIC_PRINT(array1);
    GENERIC_PRINT(array2);
    GENERIC_PRINT(array3);

    return 0;
}

但会产生以下警告:

main.c:16:78: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]                                   
main.c:25:63: note: in expansion of macro ‘U8_ARRAY_EQUAL’                                                                      
main.c:69:5: note: in expansion of macro ‘GENERIC_EQUAL’                                                                        
main.c:17:57: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]                                   
[...]
main.c:81:5: note: in expansion of macro ‘GENERIC_PRINT’                                                                        
main.c:35:53: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]                
[...]                                                                                                     
main.c:31:40: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘uint8_t * {aka unsigned char *}’ [  
-Wformat=]                                                                                                                      
main.c:70:50: note: in expansion of macro ‘INTEGER_PRINT’                                                                       
main.c:97:5: note: in expansion of macro ‘GENERIC_PRINT’                                                  

有没有办法避免第一个警告 [-Wint-to-pointer-cast]?

没有演员表我不能打电话...

所以,这里的问题是如何在每个宏中使用指针。

例如,宏 U8_ARRAY_EQUAL(integ1, integ2) 扩展为:

(memcmp((uint8_t *)integ1, (uint8_t *)integ2, sizeof(integ2)/sizeof(uint8_t)) == 0)

这意味着您将 integ1 和 integ2 的值转换为指针,而不是它们的内存地址。

解决此问题的方法是将宏定义为:

#define U8_ARRAY_EQUAL(observed,expected) (memcmp((uint8_t *)&observed, (uint8_t *)&expected, sizeof(expected)/sizeof(uint8_t)) == 0)

注意到 & 了吗?这样你实际上是在告诉 memcmp 比较包含 integ1integ2 的内存区域,而不是转换它们的值并尝试将它们用作内存地址。