在C中对指针进行类型转换

时间:2013-01-17 07:13:40

标签: c pointers casting

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

  1. 在指点指针时应该记住什么?
  2. 结果指针可能会出现什么异常/错误?
  3. 避免异常/错误的最佳做法是什么?

3 个答案:

答案 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 *)&rect;
  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语言,我认为阅读整个被删节是强制性的。