Should/Do 我通常在 C 中转换一个 void 指针?

Should/Do I cast a void pointer in C in general?

Do I cast the result of malloc? 中说,您不需要强制转换 malloc() 函数或其家族成员之一返回的 void 指针,因为自标准以来它可以省略,这可能会导致一些问题。

但是一般情况下 void 指针的转换呢?转换 void 指针的一般方法有什么不同吗?

有两种正确的情况,您需要进行演员表:

  • 将指向 void 的指针转换回其原始的非 void 类型,而不将结果分配给变量(分配包括初始化,或传递它作为参数)。

  • 让愚蠢的编译器静音,它会发出有关缩小转换的警告。 C11/C18 Annex I:

    1. An implementation may generate warnings in many situations, none of which are specified as part of this International Standard. The following are a few of the more common situations.

    2. [...]

      • An implicit narrowing conversion is encountered, such as the assignment of a long int or a double to an int, or a pointer to void to a pointer to any type other than a character type (6.3).

对于第一部分:您几乎总是可以使用临时变量。例如你可以写

int comparator(const void *a, const void *b)  
{ 
    int sa = ((const struct foo *)a)->bar; 
    int sb = ((const struct foo *)b)->bar;  
    return (sa > sb) - (sa < sb); 
} 

int comparator(const void *a, const void *b)  
{ 
    const struct foo *sa = a; 
    const struct foo *sb = b;  
    return (sa->bar > sb->bar) - (sa->bar < sb->bar); 
} 

- 它们的按键次数几乎相同。

对于第二种情况,您只需要避免使用此类编译器或尝试使用一些开关关闭这种唠叨。


除此之外,问题是 "should I have a cast where it is not needed"。在 C 程序中有许多东西不是 必需的 但为了清楚起见而添加的。例如缩进或换行!添加它们使事情变得更加清晰。问题是例如从 malloc 中为 return 值添加一个无用的转换是否会使其更具可读性:

char *foo = malloc(42);

对比

char *foo = (char *)malloc(42);

即使没有转换,结果也应该转换为 char * 或至少 foo 的结果不是很明显吗?

当你有一个void*时,你可以隐式地将它转换为任何指针类型。 这仅适用于 void*。它对 double* 不起作用,对 int 也不起作用,后者甚至不是指针。

添加强制转换时,您扩展了允许的输入类型集。突然之间,任何 指针都可以进行转换,任何整型

现在,如果将 int 转换为 myStruct* 会怎样?确切地。废话。您希望编译器对此抛出错误。


同样,如果您有一个指针,并将其隐式转换为 void*,这仅适用于指针(和 0 文字)。如果你添加了一个强制转换,你就失去了对这个值实际上是一个指针的检查。现在转换与 char 作为输入一样有效。

当您将 'a' 转换为指针时会发生什么?确切地。废话。您希望编译器对此抛出错误。


所以,请不要添加不必要的转换。它们总是会增加编译器未发现错误的可能性。如果您必须通过 void* 传递指针,请确保它仅适用于指针。