我知道指向一种类型的指针可能会被转换为另一种类型的指针。我有三个问题:
答案 0 :(得分:9)
编写良好的程序通常不会使用很多指针类型转换。例如,可能需要为 malloc 使用ptr类型转换(声明为(void *)malloc(...)
),但在C中甚至不需要(虽然有些编译器可能会抱怨)。
int *p = malloc(sizeof(int)); // no need of (int *)malloc(...)
但是在系统应用程序中,有时您希望使用技巧来执行二进制或特定操作 - 而C(一种接近机器结构的语言)很方便。例如,你想要分析 double 的二进制结构(遵循IEEE 754实现),使用二进制元素更简单,你可以声明
typedef unsigned char byte;
double d = 0.9;
byte *p = (byte *)&d;
int i;
for (i=0 ; i<sizeof(double) ; i++) { ... work with b ... }
您也可以使用 union ,这是一个例子。
更复杂的利用可能是C++ polymorphism的模拟,需要在某处存储“类”(结构)层次结构以记住什么是什么,并执行指针类型转换以具有例如父级“class”指针变量指向派生类的某个时间(也参见C ++链接)
CRectangle rect;
CPolygon *p = (CPolygon *)▭
p->whatami = POLY_RECTANGLE; // a way to simulate polymorphism ...
process_poly ( p );
但在这种情况下,也许直接使用C ++会更好!
在开发开始之前,指针类型转换将小心用于确定的情况,这些情况是程序分析的一部分。
指针类型潜在危险
s1 *p = (s1 *)&s2;
:依赖于它们的大小和对齐可能会导致错误(但公平地说,熟练的C程序员不会犯上述错误......)
最佳做法
答案 1 :(得分:3)
在普通C中,您可以将任何指针类型转换为任何其他指针类型。如果您将指针转换为不兼容的类型,或者错误地写入内存,则可能会从应用程序中获得分段错误或意外结果。
以下是构建结构指针的示例代码:
struct Entity {
int type;
}
struct DetailedEntity1 {
int type;
short val1;
}
struct DetailedEntity2 {
int type;
long val;
long val2;
}
// random code:
struct Entity* ent = (struct Entity*)ptr;
//bad:
struct DetailedEntity1* ent1 = (struct DetailedEntity1*)ent;
int a = ent->val; // may be an error here, invalid read
ent->val = 117; // possible invali write
//OK:
if (ent->type == DETAILED_ENTITY_1) {
((struct DetailedEntity1*)ent)->val1;
} else if (ent->type == DETAILED_ENTITY_2) {
((struct DetailedEntity2*)ent)->val2;
}
对于函数指针 - 你应该总是使用完全符合声明的函数。否则,您可能会收到意外结果或段错误。
当从指针转换为指针(结构与否)时,必须以完全相同的方式确保内存为aligned。在构建整个结构时,最好的方法是确保它在开始时使用相同变量的相同顺序,并仅在“公共标题”之后区分结构。还要记住,内存对齐可能因机器而异,因此您不能将结构指针作为字节数组发送并将其作为字节数组接收。您可能会遇到意外行为甚至是段错误。
当构建较小到较大的变量指针时,您必须非常小心。请考虑以下代码:
char* ptr = malloc (16);
ptr++;
uint64_t* uintPtr = ptr; // may cause an error, memory is not properly aligned
而且,您应遵循strict aliasing规则。
答案 2 :(得分:0)
您可能需要查看由Steve Summit维护的 the C-faq (过去曾在新闻组中发布,这意味着它已被很多人阅读和更新当时最好的程序员,有时候是语言本身的概念。
还有一个 abridged version ,这可能更适合,但仍非常,非常,非常非常有用。如果你使用C语言,我认为阅读整个被删节是强制性的。