18

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?

  • 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 '14 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 '14 at 7:41
  • 1
    Lots (mostly from a managed-language perspective) on Eric Lippert's blog in the cast operator category – AakashM Jan 17 '14 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? – Alexander Torstling Jan 20 '14 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 '14 at 15:03
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?

  • 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. – Alexander Torstling Jan 20 '14 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 '14 at 1:19
  • Except that converting from T* to void* and back is always well-defined. – Miles Rout Jan 22 '14 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 '14 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 '14 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
    Also: "To assign a certain role to (an actor)". – Kelly Thomas Jan 17 '14 at 11:30
  • Yup. I'm sure this is the best. +1. – david.pfx Jan 21 '14 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.

  • 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 – underscore_d Jul 19 '16 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
    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 '14 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 '14 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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