C语言 C 中指针的类型转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14373924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:04:13  来源:igfitidea点击:

Typecasting of pointers in C

cpointerscasting

提问by user1871762

I know a pointer to one type may be converted to a pointer of another type. I have three questions:

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

  1. What should kept in mind while typecasting pointers?
  2. What are the exceptions/error may come in resulting pointer?
  3. What are best practices to avoid exceptions/errors?
  1. 类型转换指针时应该记住什么?
  2. 结果指针中可能出现哪些异常/错误?
  3. 避免异常/错误的最佳实践是什么?

采纳答案by e2-e4

A program well written usually does not use much pointer typecasting. There could be a need to use ptr typecast for mallocfor instance (declared (void *)malloc(...)), but it is not even necessary in C (while a few compilers may complain).

编写好的程序通常不会使用太多的指针类型转换。例如,可能需要对malloc使用 ptr 类型转换(声明(void *)malloc(...)),但在 C 中甚至没有必要(虽然一些编译器可能会抱怨)。

  int *p = malloc(sizeof(int)); // no need of (int *)malloc(...)

However in system applications, sometimes you want to use a trick to perform binary or specific operation - and C, a language close to the machine structure, is convenient for that. For instance say you want to analyze the binary structure of a double(that follows thee IEEE 754 implementation), and working with binary elements is simpler, you may declare

然而在系统应用中,有时你想使用一个技巧来执行二进制或特定操作——而 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 ... }

You may also use an union, this is an exemple.

您也可以使用union,这是一个例子。

A more complex utilisation could be the simulation of the C++ polymorphism, that requires to store the "classes" (structures) hierarchy somewhere to remember what is what, and perform pointer typecasting to have, for instance, a parent "class" pointer variable to point at some time to a derived class (see the C++ link also)

更复杂的利用可能是C++ 多态性的模拟,它需要将“类”(结构)层次结构存储在某处以记住什么是什么,并执行指针类型转换以具有例如父“类”指针变量在某个时间指向派生类(另请参阅 C++ 链接)

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

But in this case, maybe it's better to directly use C++!

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

Pointer typecast is to be used carefullyfor well determinedsituations that are part of the program analysis - before development starts.

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

Pointer typecast potential dangers

指针类型转换的潜在危险

  • use them when it's not necessary - that is error prone and complexifies the program
  • pointing to an object of different size that may lead to an access overflow, wrong result...
  • pointer to two different structures like s1 *p = (s1 *)&s2;: relying on their size and alignment may lead to an error
  • 在没有必要时使用它们 - 这容易出错并使程序复杂化
  • 指向不同大小的对象可能导致访问溢出,错误结果...
  • 指向两个不同结构的指针,例如s1 *p = (s1 *)&s2;:依赖它们的大小和对齐可能会导致错误

(But to be fair, a skilled C programmer wouldn't commit the above mistakes...)

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

Best practice

最佳实践

  • use them only if you do need them, and comment the part well that explains why it is necessary
  • know what you are doing - again a skilled programmer may use tons of pointer typecasts without fail, i.e. don't try and see, it may work on such system / version / OS, and may not work on another one
  • 仅在您确实需要它们时才使用它们,并很好地注释说明为什么需要它们的部分
  • 知道你在做什么 - 再一次,一个熟练的程序员可能会使用大量的指针类型转换而不会失败,即不要尝试看,它可能在这样的系统/版本/操作系统上工作,而在另一个系统/版​​本/操作系统上可能不起作用

回答by Dariusz

In plain C you can cast any pointer type to any other pointer type. If you cast a pointer to or from an uncompatible type, and incorrectly write the memory, you may get a segmentation fault or unexpected results from your application.

在普通 C 中,您可以将任何指针类型转换为任何其他指针类型。如果您向或从不兼容的类型强制转换指针,并且错误地写入内存,您可能会从应用程序中获得分段错误或意外结果。

Here is a sample code of casting structure pointers:

以下是转换结构指针的示例代码:

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;
} 

As for function pointers - you should always use functions which exactly fit the declaration. Otherwise you may get unexpected results or segfaults.

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

When casting from pointer to pointer (structure or not) you must ensure that the memory is alignedin the exact same way. When casting entire structures the best way to ensure it is to use the same order of the same variables at the start, and differentiating structures only after the "common header". Also remember, that memory alignment may differ from machine to machine, so you can't just send a struct pointer as a byte array and receive it as byte array. You may experience unexpected behaviour or even segfaults.

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

When casting smaller to larger variable pointers, you must be very careful. Consider this code:

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

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

And also, there is the strict aliasingrule that you should follow.

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

回答by Olivier Dulac

You probably need a look at ... the C-faqmaintained by Steve Summit (which used to be posted in the newsgroups, which means it was read and updated by a lot of the best programmers at the time, sometimes the conceptors of the langage itself).

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

There is an abridged versiontoo, which is maybe more palatable and still very, very, very, very useful. Reading the whole abridged is, I believe, mandatory if you use C.

还有一个删节版,它可能更可口,但仍然非常、非常、非常、非常有用。我相信,如果您使用 C,则必须阅读全文。