Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some misunderstand about casting in generic function

I have some misunderstanding of the tutorial from my class. There is function called print_Arr(), it's generic function that gets pointer to arrays of double or integers and prints it.

Here is the code:

int  main() {
    int  a[] = { 2,7,6,4,1 };
    double b[] = { 12.5,2.7,3.0,5.5,5.9,1.0 };

    print_Arr(a, sizeof(a)/sizeof(a[0]), sizeof(int), print_int);
    print_Arr(b, sizeof(b)/sizeof(b[0]), sizeof(double), print_double);
}

void print_Arr(void* a, int size, int m, void (*print_func)(void* )) {

    for (int i = 0; i <= size-1; i++)
    {
        print_func((char*)a + m*i);
    }
}

void print_int(int* p) {

    printf("%d\n", *p);
}

void print_double(double* num) {

    printf("%f\n", *num);
}

Why do I have to make cast a to (char*) in this row:

print_func((char*)a + m*i);

I sent to print_Arr() generic function two type of arrays integers or doubles, thus it is logically to cast a to int * or to double*.

But why is it casted to char*? What do I miss?

like image 428
Michael Avatar asked May 12 '26 04:05

Michael


2 Answers

First, a word on why the cast is needed:

Pointer arithmetic makes use of the size of the type being pointed to. void is a forever incomplete type, that cannot be completed, so pointer arithmetic is not possible on a pointer to void type.

To add, for the additive operators, quoting from C11, chapter §6.5.6, constraints:

For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.

and, from chapter §6.2.5,

The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.


That said, why the cast is to char* :

Pointer arithmetic makes use of the type being pointed to. Quoting the spec once again

[...] if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist.

Here, look at your construct:

      ((char*)a + m*i);

where m is the size of the actual object type pointed to by the actual argument. So, if you cast the pointer to the actual type, the calculation would be wrong. To present a comparison, say:

  • sizeof (char) is 1, mandated by standard.
  • sizeof (int) == 4 , say in your platform.

So, for an array int arr[ ] = {1, 2, 3, 4}, the expressions

  • (char*)a + (sizeof(int)*1) and
  • (int*) a + 1

are equivalent.

Finally, touching the topic of converting another type of pointer to char* and accessing it:

[...] 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. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object. [....]

like image 159
Sourav Ghosh Avatar answered May 14 '26 17:05

Sourav Ghosh


You need the char * cast because you do pointer arithmetic on the pointer, to get a byte offset from the beginning, but you can't do that on a void *.

like image 23
Some programmer dude Avatar answered May 14 '26 19:05

Some programmer dude