[Question about good practice #1] Cast or not Cast ?

Hello everyone,

first of all I'm not a native english speaker so sorry in case of misspelling.

In my current practice I have the habit to use cast to work directly with the memory. But I heard that some peoples are considering that like a bad practice.

this is an example on the way I use casting:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
void *ft_memchr(const void *ptr, int value, int num)
{
    int i;
    
    i = 0;
    while (i < num)
    {
        if (*((char *)ptr + i) == value)
            return ((void *)((char *)ptr + i));
        i++;
    }
    return (0);
}


Like I said my primary goal is to work with memory in the way I want to. So using cast let me for example doing pointer arithmetic.

I don't understand why we need to be aware of casting when it can be really useful.

Thank you :)


Edited by bewwys on Reason: Initial post
There's nothing wrong with casting memory. Memory is just a bunch of bytes, it's up to you how you interpret them. It gets a little hairy when you use a C++ feature, though: inheritance. C++ has a bunch of casting operators to deal with different types of casting: static_cast, reinterpret_cast, dynamic_cast, etc...

reinterpret_cast is the same as a C-style cast, no checks, no guarantees. A static_cast will have some checks to make sure one type can be converted to the other one.

A dynamic_cast will use RTTI (Run Time Type Information) to safely cast through the inheritance chain (returns NULL if the cast is invalid). For example, a C-style cast will fail when casting between parents in a multiple inheritance situation.

In your example, I would probably ask why don't you pass a const char* ptr instead of a const void*, to avoid the cast inside the function, but there's nothing wrong with it.

As an aside, I tend to use a cast "operator" that makes it more explicit, easier to search for and doesn't break the C-style casting:
1
2
3
4
#define cast(type) (type)

// in code...
float *array = cast(float*) AllocArray(10, sizeof(float));



Edited by Marc Costa on
I'm not sure I understand question. IMHO the answer is simple - you do the cast when you need cast, and you don't do the cast when you don't need to.

In your example you need a cast. Because you cannot dereference ptr pointer - it points to void type, compiler won't know what to do with void type.
But I would write your code example like this:
1
2
3
4
5
6
7
8
    char* ptr8 = (char*)ptr;
    i = 0;
    while (i < num)
    {
        if (ptr8[i] == value)
            return ptr8 + i;
        i++;
    }

Much simpler to read and understand what's happening. And if you write C instead of C++ then you can simplify first line to this:
1
const char* ptr8 = ptr;

Casts to and from void* are implicit in C.

Edited by Mārtiņš Možeiko on
Thank you,

that's much clear.
unfortunately I need to respect the function def given by the exercice.

I really like the way you handle the cast with the def macro.

Thank you really much.


:-)



mmozeiko
I'm not sure I understand question. IMHO the answer is simple - you do the cast when you need cast, and you don't do the cast when you don't need to.

In your example you need a cast. Because you cannot dereference ptr pointer - it points to void type, compiler won't know what to do with void type.
But I would write your code example like this:
1
2
3
4
5
6
7
8
    char* ptr8 = (char*)ptr;
    i = 0;
    while (i < num)
    {
        if (ptr8[i] == value)
            return ptr8 + i;
        i++;
    }

Much simpler to read and understand what's happening. And if you write C instead of C++ then you can simplify first line to this:
1
const char* ptr8 = ptr;

Casts to and from void* are implicit in C.


I know many peoples who tells me don't deal with cast… I don' understand why. Maybe they encountered bad experience with it. ^^


bewwys

I know many peoples who tells me don't deal with cast… I don' understand why. Maybe they encountered bad experience with it. ^^




It's because you are circumventing the type system and the safety it brings you. And most of the time there are ways to do what you need without the cast.
Wasn't there some sort of undefined behavior related to casting things to "wrong types"?
Its only undefined if you cast between pointer types with different alignment requirements. So short* -> float* is undefined. And between function pointers vs non-function pointers.
But casting pointer types from and to void* is perfectly legal cast. Also it is legal to cast non-function pointer types to char*.