我知道一个类型的指针可以转换为另一个类型的指针。 我有三个问题:
- 类型转换指针时应该注意什么?
- 可能会出现哪些异常/错误的指针?
- 有哪些最佳实践可以避免异常/错误?
通常情况下,良好编写的程序不会使用过多的指针类型转换。例如,在malloc中可能需要使用ptr类型转换(声明为(void *)malloc(...)
),但在C语言中甚至没有必要(尽管有些编译器可能会发出警告)。
int *p = malloc(sizeof(int)); // no need of (int *)malloc(...)
然而,在系统应用程序中,有时您希望使用技巧执行二进制或特定操作 - 而C语言,作为一种接近于机器结构的语言,非常方便。例如,假设您想要分析遵循IEEE 754实现的double的二进制结构,并且使用二进制元素更简单,那么您可以声明:
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++多态性,这需要在某个地方存储"类"(结构体)的层次结构以记住每个类别,然后执行指针类型转换,例如,父级"类"指针变量在某些时候指向派生类(请参见C ++链接)。
CRectangle rect;
CPolygon *p = (CPolygon *)▭
p->whatami = POLY_RECTANGLE; // a way to simulate polymorphism ...
process_poly ( p );
但在这种情况下,也许直接使用C++更好!
指针类型转换应该谨慎使用,在程序分析的确定情况下使用——在开发开始之前。
指针类型转换的潜在危险
s1 *p = (s1 *)&s2;
:依赖它们的大小和对齐方式可能会导致错误(不过,有经验的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;
}
char* ptr = malloc (16);
ptr++;
uint64_t* uintPtr = ptr; // may cause an error, memory is not properly aligned
void *
(又名qsort()
类型工作)进行不透明隐藏之外,在一般情况下最好完全避免使用它。最后,一个更微妙的问题(也是大头痛的根源),就是数据对齐,但这一点根本没有被提到。 - WhozCraigunsigned char *
强制转换为float *
将在许多平台上在您解引用浮点指针时导致总线错误),因此我们必须就此问题保持不同意见。 - WhozCraig