抑制从 void ** 到另一个 ** 的隐式类型转换警告的方法?
Way to supress warning for implicit typecasting from void ** to another **?
我有一个小项目,其中包括处理指针数组,为了方便我制作了一个 .h 文件来处理它,方法是使用 void 指针进行操作,然后 returns 最终产品,即函数原型会类似于 void **ptr_array_add(void **ptr_array, void *new_ptr);
。但是,每当我使用此函数而没有明确地将我的指针类型转换为 void **
并返回到它们的原始类型时,gcc 会在转换时抛出警告。
我做的事情不安全吗?我假设 gcc 发出警告一定是有原因的,但据我所知,void **
与任何其他类型的指针数组相同,因为所有指针都是 8 个字节长(或者无论它们有多长) ,关键是它们的长度都是一样的),如果我所做的没有问题,有没有办法在每次调用这些函数时都不必添加 20 个字符的类型转换来抑制警告?
谢谢
C 类型系统只有一种特殊的泛型指针,那就是void*
,而且只有那一种。但是,这不适用于“递归”; void**
没有什么特别之处。因此,您可以分配给 void**
的唯一类型是另一个 void**
或 void*
.
的地址
因此,为了使用您发布的函数,您需要在调用方声明一个 void*
,将其传递给函数,然后将 void*
转换为相关的对象指针之后:
void* tmp;
... ptr_array_add(&tmp, ...);
int* some_other_pointer = tmp; // assuming that the actual data type is indeed int
Is what I'm doing unsafe?
是的,如果指针被取消引用为它实际指向的类型以外的其他类型,则通过转换为“关闭警告”强制执行无效指针转换将导致未定义的行为。具体问题是严格的指针别名、指针大小和指针的陷阱表示,所有这些在理论上都会产生细微的错误和崩溃。
但在实践中,非奇异系统上的大多数指针可能在内部具有相同的大小和表示。像 CUDA 这样的一些库甚至在 void**
和其他指针到指针之间使用脏转换作为 API 的一部分。但是,当您这样做时,C 标准不支持保证任何确定性行为。
如果这是一个指针接一个指针的数组,您可能可以更改签名以使用 void*。我举一个简单的例子,将新指针写入数组的第二个条目并 returning 数组的旧开始。
void* ptr_array_add(void* ptr_array, void* new_ptr) {
void** entries = (void**)ptr_array;
entries[1] = new_ptr;
return (void*)entries;
}
所有强制转换现在都在函数内部。
您的用户代码必须将数组保持为 void*.
如果您还想将 returned 值转换为特定类型,例如int**,不能自动完成。
您必须为您使用的每种类型创建特定的包装器。
使用 C++ 编译器会有模板。
仅对于 C,您可以使用预处理器宏自动创建包装函数。
您也可以(在 C 中)为 return 值使用输出参数,如果您可以完全更改函数签名:
// out_ptr_array points to a location, where the result is stored
// in your terminology it would be a void***, but we actually use void*
// in_ptr_array is void**, but we actually use void*
// new_ptr is void*
void ptr_array_add(void* out_ptr_array, void* in_ptr_array, void* new_ptr) {
void** entries = (void**)in_ptr_array;
entries[1] = new_ptr;
void** returnarray = (void**)out_ptr_array;
*returnarray = entries; // of course we can also return a new/another address to an array
}
// no warnings!
#include <stdio.h>
int main() {
int* array[3]; // array of pointers to int
int** arrayptrin; // location of array
arrayptrin = &array[0];
int** arrayptrout; // return value of function
int a = 4; // value
int* pa = &a; // pointer to value for adding
// call function with parameters
// where to store result (new array location?), array location, new pointer
ptr_array_add(&arrayptrout, arrayptrin, pa);
int* pb = arrayptrout[1]; // read one pointer
printf("Result: %d\n", *pb); // print, value on pointer location (prints: 4)
}
在这个例子中,我们不需要在头函数之外进行任何转换。根本没有发出警告。
我有一个小项目,其中包括处理指针数组,为了方便我制作了一个 .h 文件来处理它,方法是使用 void 指针进行操作,然后 returns 最终产品,即函数原型会类似于 void **ptr_array_add(void **ptr_array, void *new_ptr);
。但是,每当我使用此函数而没有明确地将我的指针类型转换为 void **
并返回到它们的原始类型时,gcc 会在转换时抛出警告。
我做的事情不安全吗?我假设 gcc 发出警告一定是有原因的,但据我所知,void **
与任何其他类型的指针数组相同,因为所有指针都是 8 个字节长(或者无论它们有多长) ,关键是它们的长度都是一样的),如果我所做的没有问题,有没有办法在每次调用这些函数时都不必添加 20 个字符的类型转换来抑制警告?
谢谢
C 类型系统只有一种特殊的泛型指针,那就是void*
,而且只有那一种。但是,这不适用于“递归”; void**
没有什么特别之处。因此,您可以分配给 void**
的唯一类型是另一个 void**
或 void*
.
因此,为了使用您发布的函数,您需要在调用方声明一个 void*
,将其传递给函数,然后将 void*
转换为相关的对象指针之后:
void* tmp;
... ptr_array_add(&tmp, ...);
int* some_other_pointer = tmp; // assuming that the actual data type is indeed int
Is what I'm doing unsafe?
是的,如果指针被取消引用为它实际指向的类型以外的其他类型,则通过转换为“关闭警告”强制执行无效指针转换将导致未定义的行为。具体问题是严格的指针别名、指针大小和指针的陷阱表示,所有这些在理论上都会产生细微的错误和崩溃。
但在实践中,非奇异系统上的大多数指针可能在内部具有相同的大小和表示。像 CUDA 这样的一些库甚至在 void**
和其他指针到指针之间使用脏转换作为 API 的一部分。但是,当您这样做时,C 标准不支持保证任何确定性行为。
如果这是一个指针接一个指针的数组,您可能可以更改签名以使用 void*。我举一个简单的例子,将新指针写入数组的第二个条目并 returning 数组的旧开始。
void* ptr_array_add(void* ptr_array, void* new_ptr) {
void** entries = (void**)ptr_array;
entries[1] = new_ptr;
return (void*)entries;
}
所有强制转换现在都在函数内部。 您的用户代码必须将数组保持为 void*.
如果您还想将 returned 值转换为特定类型,例如int**,不能自动完成。
您必须为您使用的每种类型创建特定的包装器。 使用 C++ 编译器会有模板。
仅对于 C,您可以使用预处理器宏自动创建包装函数。
您也可以(在 C 中)为 return 值使用输出参数,如果您可以完全更改函数签名:
// out_ptr_array points to a location, where the result is stored
// in your terminology it would be a void***, but we actually use void*
// in_ptr_array is void**, but we actually use void*
// new_ptr is void*
void ptr_array_add(void* out_ptr_array, void* in_ptr_array, void* new_ptr) {
void** entries = (void**)in_ptr_array;
entries[1] = new_ptr;
void** returnarray = (void**)out_ptr_array;
*returnarray = entries; // of course we can also return a new/another address to an array
}
// no warnings!
#include <stdio.h>
int main() {
int* array[3]; // array of pointers to int
int** arrayptrin; // location of array
arrayptrin = &array[0];
int** arrayptrout; // return value of function
int a = 4; // value
int* pa = &a; // pointer to value for adding
// call function with parameters
// where to store result (new array location?), array location, new pointer
ptr_array_add(&arrayptrout, arrayptrin, pa);
int* pb = arrayptrout[1]; // read one pointer
printf("Result: %d\n", *pb); // print, value on pointer location (prints: 4)
}
在这个例子中,我们不需要在头函数之外进行任何转换。根本没有发出警告。