避免在 _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
比较包含 integ1
和 integ2
的内存区域,而不是转换它们的值并尝试将它们用作内存地址。
以下代码按预期工作,
#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
比较包含 integ1
和 integ2
的内存区域,而不是转换它们的值并尝试将它们用作内存地址。