20

When coding in low level languages like C I find that casting sometimes means 'reinterpret these bytes as if it had always been of this other type' and at other times as 'convert this value intelligently into this other type'.

What is the original meaning of the word and is there any consistency in when to expect a conversion and when to expect a raw reinterpretation?

6
  • what is in Wikipedia article that you don't understand? "type conversion, typecasting, and coercion are different ways of, implicitly or explicitly, changing an entity of one data type into another... Each programming language has its own rules on how types can be converted..."
    – gnat
    Jan 17, 2014 at 7:18
  • The original meaning of "to cast" has nothing in commong with programming, see here merriam-webster.com/dictionary/cast
    – Doc Brown
    Jan 17, 2014 at 7:41
  • 1
    Lots (mostly from a managed-language perspective) on Eric Lippert's blog in the cast operator category
    – AakashM
    Jan 17, 2014 at 11:20
  • 1
    @gnat: I'm not sure if that's a serious question or just a trolling attempt. But I would like to know how to know what the compiler will do: convert, cast or coerce? What are the rules of thumb? Jan 20, 2014 at 8:36
  • 1
    @DocBrown I think the term cast in the computing sense is more similar to casting in the metallurgy sense, whereby the shape of a molten metal is reformed when poured into a mold: britannica.com/EBchecked/topic/377665/metallurgy/81884/Casting
    – KChaloux
    Jan 21, 2014 at 15:03

4 Answers 4

10

Casting in C is unique, quite unlike other languages. It is also never intelligent.

Casting in C converts values from one type to another using carefully defined rules. If you really need to know, read the standard. Otherwise the main points are:

  1. Conversion between integer types preserve the value, if possible. If the destination has more bits this is widening and generally safe, but may involve sign extension. If narrower, bits will be lost.
  2. Conversion between pointer types preserves the pointer value, but the results are often undefined, often non-portable and often useful for advanced scenarios.
  3. Conversion between integer types and pointers are OK if the integer is big enough, and preserves the bit pattern (whatever that might happen to mean). If the integer is too small, the result is undefined but not useful. As a rule 'long' is wide enough for 'void *', but no guarantees! Pointers created this way may be invalid, in all kinds of interesting ways.
  4. Conversion between float and integer types are arithmetic conversions as defined by an appropriate library routine (with truncation, not rounding).
  5. You can cast the return value of a function to void. I never have. It does nothing.

Some casts are applied implicitly, and in some of those the compiler will issue a warning. Best to heed the warnings!

The dictionary definition for cast is best ignored, as being unhelpful. Many casts are better described by the terms conversion or coercion, so it's worth knowing those too.

C++ is MUCH more complicated, but you didn't ask that, did you?

6
  • I'm interested in rules of thumb, and not miniscule detail, but I am interested in other languages than C if that helps clearing things up. Jan 20, 2014 at 8:38
  • 2
    What I've given here is as generic as is reasonable. To write real, low level professional C/C++ code the miniscule detail is critical. Most languages just don't have this kind of issue in their type conversions. Sorry if it doesn't solve your problem.
    – david.pfx
    Jan 21, 2014 at 1:19
  • Except that converting from T* to void* and back is always well-defined.
    – Miles Rout
    Jan 22, 2014 at 3:14
  • @Miles: Actually, converting T* to any U* and back is required to preserve the original pointer value. In my answer I only said 'often undefined' to keep it short, 'cos some of the details are very messy.
    – david.pfx
    Jan 22, 2014 at 13:48
  • 1
    @supercat: See n1570 S6.3.2.3. Converting/round-tripping between T*, U* and void* always preserves the pointer value with just one exception. If any T* is not correctly aligned, it's undefined behaviour. I accept your point, but only to that extent.
    – david.pfx
    May 7, 2014 at 11:48
2

This part of the Webster dictionary gives the proper definition:

a : to give a shape to (a substance) by pouring in liquid or plastic form into a mold and letting harden without pressure
b : to form by this process

So, before casting, your "object" (not literally an OOP object) is in a given shape (type). When you re-cast it, that is "pour concrete" around it to make it into a new shape, that is what you do with casting. You have a number as a hexagon-shaped integer, and after casting, you will get a rectangle-shaped string.

2
  • 3
    Also: "To assign a certain role to (an actor)". Jan 17, 2014 at 11:30
  • Yup. I'm sure this is the best. +1.
    – david.pfx
    Jan 21, 2014 at 2:02
2

It may be useful to separate C casts to two groups:

  1. Numeric casts - convert a number between one representation to another, attempting to keep the value. For example - (int)3.1 would be 3. There are exact rules defining what happens when the exact value can't be kept.

  2. Pointer casts - Keep the memory address, but change the way it's dereferenced. For example, for float x=3.5, *(int *)&x will give 1080033280 - this integer is represented by the same bit pattern that represents the float 3.5.

1
  • Keep the memory address, but change the way it's dereferenced. Dereferencing a type-punned pointer is not defined. The Standard only guarantees casting from A * to B * & back will produce the same A *, which may not have been valid to dereference in the 1st place - or that if B * is a char *, it can be used to read the object representation of any type. For all other types, dereferencing B * pointer is type-punning, UB, & violates strict aliasing. Anyway, even if the compiler didn't trash the above example 2 for that reason, you're making unportable assumptions about bit patterns Jul 19, 2016 at 6:15
1
cast (v): to receive form in a mold

In C++ the various kinds of casts can be made more explicit, with reinterpret_cast meaning "treat these bytes as if they were already this other thing". In C you can make that absolutely explicit by using a union, casting with the (type) operator will attempt to keep the result numerically equivalent, up to loss of precision.

2
  • 2
    In C pointer casts are always reinterpret and value casts always preserve value as best possible. In C++ there are multiple ways to do pointer cast, which is why there are the more explicit cast types.
    – Jan Hudec
    Jan 17, 2014 at 9:03
  • C pointer-cast semantics aren't necessarily "reinterpret". It would be legitimate for a processor that used word addressing but wanted to interact nicely with byte-based code to have an int* that was one word and a char* that was two words [with the second byte selecting the high or low byte of a word]. Casting an (int*) to (char*) would require the addition of an extra word which should be whatever value would specify the the first byte of the int.
    – supercat
    May 6, 2014 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.