所以今天我遇到了这种情况。我有这样的代码
void some_handler(some_stuct_t * p_evt_type)
{
uint16_t a = ((uint16_t )p_evt_type->p_instance->p_instance_handler);
(a)++;
}
这是givinig me警告,但当我更改代码以转换为指针时,它看起来完全正确。
void some_handler(some_stuct_t * p_evt_type)
{
uint16_t * a = ((uint16_t *)p_evt_type->p_instance->p_instance_handler);
(*a)++;
}
p_instance_handler
的类型为
(void *)
直接投射到价值有什么问题?
答案 0 :(得分:2)
INT36-C. Converting a pointer to integer or integer to pointer
整数和指针之间的转换可能不合需要 后果取决于 implementation。 根据C标准,子条款6.3.2.3 [ISO/IEC 9899:2011],
整数可以转换为任何指针类型。除了以前 指定,结果是实现定义的,可能不是 正确对齐,可能不指向引用的实体 类型,可能是陷阱表示。
任何指针类型都可以转换为整数类型。除了 之前指定的,结果是实现定义的。如果 结果不能用整数类型表示,行为是 未定义。结果不必在任何值的范围内 整数类型。
简而言之,指针和整数之间的转换是可能的,但结果是实现定义的,因此在sizeof(integer) < sizeof(pointer)
的实现中转换将不起作用。
不符合规范的代码示例
指针的大小可以大于整数的大小,例如在指针为64位且无符号整数为32位的实现中。
void f(void) { char *ptr; /* ... */ unsigned int number = (unsigned int)ptr; /* ... */ }
答案 1 :(得分:0)
虽然不需要将指针从类型转换为void 或 void转换为(这里有一些与此无关的例外情况),但转换变得非常重要当你需要降低void
指针时。如您所知,指针将其值存储为其他值的地址。处理与值相同类型的指针时,不需要任何其他强制转换,因为type
已经修复。 e.g。
int a[] = { 1, 3, 5, 7, 9 };
int *ap = a;
ap++;
printif (" ap points to : %d\n", *ap);
一切都好,没有神秘感。现在让我们采用一个函数来迭代数组中的值,将数组和元素数作为参数。但是还有另一个参数需要能够迭代传递为void *
的数组。它是什么? sizeof 构成sup a
的每个元素。
否则,由于数组作为void指针传递,指针算术会发生什么?在函数中,如果我们尝试ap++
会发生什么?
这就是问题所在。当将指针作为void指针处理时,它们使用起来非常方便,但是当它们所持有的值必须被操作时,必须对它们进行转换,以便编译器知道指向的对象的大小,这样它就可以知道{之间存在多少字节{1}}并且数组中的下一个值位于ap
。
类型转换指针还有另一个警告。必须以不违反严格别名规则的方式进行转换,并且不会发生类型双关语。请参阅C11 N1570 Committee Draft — April 12, 2011为此您需要查看第6.5(6)和(7)节,并密切关注草案中包含的注释。在不进入漏洞和资格的情况下,您可以安全地将void指针强制转换为有效类型或 char 。任何其他组合都要求存在别名冲突,从而导致类型被击中指针。
继续我们的示例,如果我们将数组ap++
传递给函数a
而不是void *
,我们的函数中需要什么才能允许指针算术运算好好工作?我们从规则6.5(6)知道我们可以转换为int *
并且不会违反严格别名规则,因此我们可以像这样处理它,其中char
是我们的数组, a
元素数量,n
数组中每个元素的大小:
sz
然后我们可以毫无问题地逐步遍历数组,同时从每个先前元素添加适当的大小/偏移量。
如果我们知道我们将通过void prnarray (void *a, size_t n, size_t sz)
{
char *ap = a;
printf ("\npointers printed from prnarray:\n\n");
while (n--) {
printf (" ap points to : %d\n", *ap);
ap += sz;
}
}
指针获取int
数组怎么办?这允许直接转换为数组的有效类型,我们不再需要担心传递大小。指针算术将处理数组内每个值的偏移,例如
void
虽然没有上一个函数那么灵活,我们不仅限于类型,但在很多情况下你会知道你作为void传递的指针类型,在这些情况下,转换为有效类型将简化您的代码。
现在将所有部分组合在一起,您可以创建一个简短的说明性示例,如下所示:
void prnarrayint (void *a, size_t n)
{
int *ap = a;
printf ("\npointers printed from prnarrayint:\n\n");
while (n--)
printf (" ap points to : %d\n", *ap++);
}
使用/输出强>
#include <stdio.h>
void prnarray (void *a, size_t n, size_t sz)
{
char *ap = a;
printf ("\npointers printed from prnarray:\n\n");
while (n--) {
printf (" ap points to : %d\n", *ap);
ap += sz;
}
}
void prnarrayint (void *a, size_t n)
{
int *ap = a;
printf ("\npointers printed from prnarrayint:\n\n");
while (n--)
printf (" ap points to : %d\n", *ap++);
}
int main (void) {
int a[] = { 1, 3, 5, 7, 9 };
int *ap = a;
size_t i, n = sizeof a/ sizeof *a;
i = n;
printf ("\npointers printed in main:\n\n");
while (i--)
printf (" ap points to : %d\n", *ap++);
prnarray (a, n, sizeof *a); /* pass/print based on sz with cast to char */
prnarrayint (a, n); /* pass/print based on effective type of array */
return 0;
}
总而言之,通用指针$ ./bin/voidpcast
pointers printed in main:
ap points to : 1
ap points to : 3
ap points to : 5
ap points to : 7
ap points to : 9
pointers printed from prnarray:
ap points to : 1
ap points to : 3
ap points to : 5
ap points to : 7
ap points to : 9
pointers printed from prnarrayint:
ap points to : 1
ap points to : 3
ap points to : 5
ap points to : 7
ap points to : 9
可以分配给/从任何类型指针返回,而不需要强制转换,但是当任何操作需要取消引用指针以获取指向的值时,然后必须对有效类型或 char 进行适当的强制转换,以符合 strict-aliasing 的规则。