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
指针的一般方法有什么不同吗?
- 应该在 C 中将
void
指针转换为另一种类型的指针吗?
- 在 C 语言中有没有我可以强制转换
void
指针的地方?
有两种正确的情况,您需要进行演员表:
将指向 void 的指针转换回其原始的非 void 类型,而不将结果分配给变量(分配包括初始化,或传递它作为参数)。
让愚蠢的编译器静音,它会发出有关缩小转换的警告。 C11/C18 Annex I:
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.
[...]
- 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*
传递指针,请确保它仅适用于指针。
在 Do I cast the result of malloc? 中说,您不需要强制转换 malloc()
函数或其家族成员之一返回的 void
指针,因为自标准以来它可以省略,这可能会导致一些问题。
但是一般情况下 void
指针的转换呢?转换 void
指针的一般方法有什么不同吗?
- 应该在 C 中将
void
指针转换为另一种类型的指针吗? - 在 C 语言中有没有我可以强制转换
void
指针的地方?
有两种正确的情况,您需要进行演员表:
将指向 void 的指针转换回其原始的非 void 类型,而不将结果分配给变量(分配包括初始化,或传递它作为参数)。
让愚蠢的编译器静音,它会发出有关缩小转换的警告。 C11/C18 Annex I:
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.
[...]
- 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*
传递指针,请确保它仅适用于指针。