为什么我必须在使用其值之前将void指针强制转换为int指针?

时间:2016-05-10 07:04:01

标签: c pointers casting

所以今天我遇到了这种情况。我有这样的代码

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 *)

直接投射到价值有什么问题?

2 个答案:

答案 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 的规则。