C++ static_cast from int* to void* to char* - can you help me to understand this code?

user2550609 picture user2550609 · Jul 4, 2013 · Viewed 8.3k times · Source

I'm a beginner in C++, and I have problem with understanding some code.

I had an exercise to do, to write function which returns size of int, and do not use sizeof() and reinterpret_cast. Someone gave me solution, but I do not understand how it works. Can you please help me to understand it? This is the code:

int intSize() {
  int intArray[10];
  int * intPtr1;
  int * intPtr2;

  intPtr1 = &intArray[1];
  intPtr2 = &intArray[2];

  //Why cast int pointer to void pointer?
  void* voidPtr1 = static_cast<void*>(intPtr1);

  //why cast void pointer to char pointer?
  char* charPtr1 = static_cast<char*>(voidPtr1);

  void* voidPtr2 = static_cast<void*>(intPtr2);
  char* charPtr2 = static_cast<char*>(voidPtr2);

  //when I try to print 'charPtr1' there is nothing printed
  //when try to print charPtr2 - charPtr1, there is correct value shown - 4, why?
  return charPtr2 - charPtr1;
}

To summarize what I don't understand is, why we have to change int* to void* and then to char* to do this task? And why we have the result when we subtract charPtr2 and charPtr1, but there is nothing shown when try to print only charPtr1?

Answer

ComicSansMS picture ComicSansMS · Jul 4, 2013

First of all, never do this in real-world code. You will blow off your leg, look like an idiot and all the cool kids will laugh at you.

That being said, here's how it works: The basic idea is that the size of an int is equal to the offset between two elements in an int array in bytes. Ints in an array are tightly packed, so the beginning of the second int comes right after the end of the first one:

int* intPtr1 = &intArray[0];
int* intPtr2 = &intArray[1];

The problem here is that when subtracting two int pointers, you won't get the difference in bytes, but the difference in ints. So intPtr2 - intPtr1 is 1, because they are 1 int apart.

But we are in C++, so we can cast pointers to anything! So instead of using int pointers, we copy the value to char pointers, which are 1 byte in size (at least on most platforms).

char* charPtr1 = reinterpret_cast<char*>(intPtr1);
char* charPtr2 = reinterpret_cast<char*>(intPtr2);

The difference charPtr2 - charPtr1 is the size in bytes. The pointers still point to the same location as before (i.e. the start of the second and first int in the array), but the difference will now be calculated in sizes of char, not in sizes of int.

Since the exercise did not allow reinterpret_cast you will have to resort to another trick. You cannot static_cast from int* to char* directly. This is C++'s way of protecting you from doing something stupid. The trick is to cast to void* first. You can static_cast any pointer type to void* and from void* to any pointer type.