21

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?
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user1871762
  • 359
  • 1
  • 2
  • 10

3 Answers3

17

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

  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

  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.

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)

  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++!

Pointer typecast is to be used carefully for well determined situations 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

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

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
Déjà vu
  • 28,223
  • 6
  • 72
  • 100
3

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.

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 aligned in 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 aliasing rule that you should follow.

Community
  • 1
  • 1
Dariusz
  • 21,561
  • 9
  • 74
  • 114
  • I think this is oversimplifying things a bit ... You can't freely cast between function pointers and pointers to data objects for instance. Also, there's no guarantee you'll get a seg fault. – unwind Jan 17 '13 at 08:02
  • I concur with @unwind. One of the worst things about pointer-casting in C is the fundamental idea itself; you're wanting to treat something as if it were something it isn't. With the exception of opaque hiding through `void *` (aka `qsort()` type work, and even there the specifics are size-based which you must supply), it is generally good to avoid it entirely. Finally one of the more subtle problems (and the source of **big** headaches), is *data alignment*, and isn't mentioned at all. – WhozCraig Jan 17 '13 at 08:11
  • @WhozCraig Thanks for reminding about data alignment. Though it isn't exactly an issue in pointer casting, mentioning it may be useful. – Dariusz Jan 17 '13 at 08:17
  • @DariuszWawer it is an *enormous* issue if the address being stored in the 'cast-to' pointer who's type requires stricter alignment than the data address it now holds complies with (i.e. casting an `unsigned char*` on an odd-memory address to a `float *` will bus-error on many platforms as soon as you dereference the float ptr), so we'll have to disagree about that. – WhozCraig Jan 17 '13 at 08:21
  • @WhozCraig Hey, I'm sensing some flustration or anger in your comment. I'm doing my best here. I added info from you to the answer. Thanks very much:) – Dariusz Jan 17 '13 at 08:30
  • @DariuszWawer Not at all, sir. I only bring up alignment because it is without a doubt the one place casting has bit me the worst in the past. Its a hard question to answer and cover all bases. I assure you I would have down-voted if I thought the answer was totally off-target. You're fine, and no, no anger or frustration to be found =P – WhozCraig Jan 17 '13 at 08:31
1

You probably need a look at ... the C-faq maintained 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).

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

Olivier Dulac
  • 3,695
  • 16
  • 31
  • I do miss having a central place to look/update things at ... Now the knowledge is spread over several websites, and some have very mistaken answers too... Anyone knows if there is a good (ie "the one everyone should go to") FAQ wiki site? – Olivier Dulac Jan 17 '13 at 08:30