3

Say I have the following c code:

int* vector = (int*)malloc(5 * sizeof(int));

malloc returns a void pointer because doesn't know what is being asked to allocate space for.

Therefore, we are casting the void pointer to an int pointer.

Does the cast actually do anything at runtime, or is it just required for compiling? If it does work at runtime, what is it doing?

Chris Snow
  • 23,813
  • 35
  • 144
  • 309
  • 5
    This is a bad example because [we don't cast the result of `malloc`](http://stackoverflow.com/q/605845/1009479) – Yu Hao Aug 07 '15 at 12:11
  • The example was a cut and paste from [here](https://books.google.co.uk/books?id=K4P32IpvyNMC&lpg=PA68&ots=_zknlOEjZm&dq=int*%20vector%20%3D%20(int*)malloc(5%20*%20sizeof(int))%3B&pg=PA68#v=onepage&q=int*%20vector%20=%20(int*)malloc(5%20*%20sizeof(int));&f=false) :( – Chris Snow Aug 07 '15 at 12:41
  • It removes inconvenient and annoying warning/error messages from the compiler and so allows your code to crash cleanly. – Martin James Aug 07 '15 at 15:39
  • @Chris Snow: It is not "required for compiling". In fact, it is bad style. "Classic" C books are notorious for bad style in the code samples they present. – AnT stands with Russia Aug 08 '15 at 00:31

4 Answers4

3

Casting of pointers is required at compile time with the notable exception of pointers to void that may be converted to or from pointers to any type without explicit cast.

What happens at run-time is not specified by the language with the exception that pointer to char and pointer to void are required to have same representation. For what remains, the only thing required is (6.3.2.3 Conversion / Pointers § 7) A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer

But on common architectures, the representation of a pointer to any object is the address of its first byte. So pointer conversion at runtime is a no-op.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Read one more sentence: `C11 draft standard §6.3.2.3 Pointers, Section 7 [...] When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object.[...]` It's not just "on common architectures", it's the law. – EOF Aug 07 '15 at 14:57
  • @EOF : the law does not say that the representation of the pointer to the object has to be the same as the one for the pointer to first char. It just says that when you convert back and forth you must get same value. It would be acceptable for some bits in pointer representation to represent the pointed type or size, while other represent the address. In such an architecture, the cast would have something to do at runtime. – Serge Ballesta Aug 07 '15 at 15:24
2

Casting a pointer could do something nontrivial. However, typically pointers of any type to a particular address all have the same representation, so the cast doesn't do anything.

That said, that is only if the code is implemented at face value; all sorts of crazy things can happen with optimization, so that the machine code comprising your executable doesn't directly correspond to the source code. (of course, in that case, there still probably isn't anything correspond to the cast)

1

The cast doesn't do anything at runtime. It's used at compile time to let the compiler know that you do in fact intend on treating one data type as another.

A void * is special, because in C (but not C++) you're allowed to assign any (non-function) pointer to or from a void * without the compiler warning you about it.

Because of this, you should never cast to or from a void *, as you're doing in your example. In the case of malloc doing so can mask the fact that you forget to #include <stdlib.h>, which can lead to some subtle bugs elsewhere in your code.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

On some old types of machine (those on which I learned to program C), the value of the char * address for a memory location was not the same as the int * address for the same location, even assuming that the address was sufficiently well aligned. The machine in question was an ICL or Three Rivers machines called the Perq.

The Perq was a micro-coded machine — you could add to its instruction set if you were good enough. Its basic addressing unit was a 16-bit word. The fact that an address was a character pointer, and whether it was the even or odd byte that was being addressed, was encoded in high-order or most significant address bits, not the least significant or low-order address bits. This was in the days when an increase from 1 MiB to 2 MiB of main memory gave about 5 times as much memory for programs to run in — because the o/s used about 3/4 MiB; handling gigabytes of memory was not considered (heck, the disk drives were much smaller than 1 GiB, let alone the main memory). Consequently, 'wasted bits' in the addresses were not an issue either.

This was also in the days long before the oldest C standard. The memory allocation functions like malloc() were defined as:

extern char *malloc();  /* No prototypes - no <stdlib.h> either */

And woe betide you if you forgot to declare the function before using it. The returned value would be horribly mismanaged and your program would crash. And, in those days, it was necessary to cast the result of malloc(). The compilers in those days didn't have options to help you spot the problems; the lint program, now relegated to the dustbin of history, was a crucial check to help ensure that your program was coded correctly.

So, on some real (but now archaic) systems, casts would really make changes to the bit pattern of a pointer.

Some mainframe systems encoded type information in their pointers — ICL 2900 Series machines were an example of that. C was hard to port to such systems.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278