21

我知道指向一种类型的指针可能会转换为另一种类型的指针。我有三个问题:

  1. 类型转换指针时应该记住什么?
  2. 结果指针中可能出现哪些异常/错误?
  3. 避免异常/错误的最佳实践是什么?
4

3 回答 3

16

一个写得好的程序通常不会使用太多的指针类型转换。例如,可能需要对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++ 多态性的模拟,这需要将“类”(结构)层次结构存储在某处以记住什么是什么,并执行指针类型转换以拥有例如父“类”指针变量有时指向派生类(另请参阅 C++ 链接)

  CRectangle rect;
  CPolygon *p = (CPolygon *)&rect;
  p->whatami = POLY_RECTANGLE; // a way to simulate polymorphism ...
  process_poly ( p );

但在这种情况下,也许直接使用C++会更好!

指针类型转换应谨慎用于作为程序分析一部分的确定情况 - 在开发开始之前。

指针类型转换的潜在危险

  • 在不需要时使用它们 - 这容易出错并使程序复杂化
  • 指向可能导致访问溢出、错误结果的不同大小的对象...
  • 指向两个不同结构的指针,例如s1 *p = (s1 *)&s2;:依赖它们的大小和对齐方式可能会导致错误

(但公平地说,一个熟练的 C 程序员不会犯上述错误......)

最佳实践

  • 仅在您确实需要它们时才使用它们,并很好地评论解释为什么需要它们的部分
  • 知道你在做什么 - 再次,一个熟练的程序员可能会使用大量的指针类型转换而不会失败,即不要尝试查看,它可能在这样的系统/版本/操作系统上工作,并且可能在另一个系统/版​​本/操作系统上不起作用
于 2013-01-17T08:43:09.707 回答
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;
} 

至于函数指针 - 您应该始终使用完全符合声明的函数。否则你可能会得到意想不到的结果或段错误。

从指针转换为指针(结构与否)时,您必须确保内存以完全相同的方式对齐。在转换整个结构时,确保它的最佳方法是在开始时使用相同变量的相同顺序,并且仅在“公共标头”之后区分结构。另请记住,内存对齐方式可能因机器而异,因此您不能仅将结构指针作为字节数组发送并作为字节数组接收。您可能会遇到意外的行为,甚至是段错误。

将较小的变量指针转换为较大的变量指针时,必须非常小心。考虑这段代码:

char* ptr = malloc (16);
ptr++;
uint64_t* uintPtr = ptr; // may cause an error, memory is not properly aligned

而且,您应该遵循严格的别名规则。

于 2013-01-17T07:22:58.183 回答
0

你可能需要看一下...由 Steve Summit 维护的 C-faq(它曾经发布在新闻组中,这意味着它被当时许多最优秀的程序员阅读和更新,有时是语言本身)。

还有一个精简版,可能更可口,但仍然非常、非常、非常、非常有用。我相信,如果你使用 C,阅读整个删节是强制性的。

于 2013-01-17T08:28:02.830 回答