3
votes

My code needs to pass an array to a void pointer (The struct has (void *) that cannot be modified). The two versions of code below produce the same output but the latter has two warnings. My question is which of the two methods is preferred? Is there a way to typecast to remove the warnings?

This version does not have warnings and produces the output as expected:

#include <stdio.h>

void test(void *var_arr, char var_1);

typedef struct {
    char chip;
    void *buffer;
}test_struct;

int main()
{
   int test_array[3] = {3,7,5};
    char var_1 = 0x20;

    printf("Hello, World!\n");

    test(&test_array, var_1);
    return 0;
}

void test(void *var_arr, char var_1)
{
    int i;

    test_struct var_ts;

    var_ts.chip = var_1;
    var_ts.buffer = var_arr;

    for (i=0; i<3; ++i)
        printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));

}

Hello, World!

The data values are : 3

The data values are : 7

The data values are : 5


This version below has two warnings but compiles and produces the output expected:

Warning(s): source_file.c: In function ‘main’: source_file.c:17:10: warning: passing argument 1 of ‘test’ from incompatible pointer type test(&test_array, var_1); ^ source_file.c:3:6: note: expected ‘int ’ but argument is of type ‘int ()[3]’ void test(int *var_arr, char var_1);

#include <stdio.h>

void test(int *var_arr, char var_1);

typedef struct {
    char chip;
    void *buffer;
}test_struct;

int main()
{
   int test_array[3] = {3,7,5};
    char var_1 = 0x20;

    printf("Hello, World!\n");

    test(&test_array, var_1);
    return 0;
}

void test(int *var_arr, char var_1)
{
    int i;

    test_struct var_ts;

    var_ts.chip = var_1;
    var_ts.buffer = (void *)var_arr;

    for (i=0; i<3; ++i)
        printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));

}
2
Remove the ampersand in the call to test(). - Bjorn A.
Note: you do not need to cast a pointer either to of from void*. If you do, it can hide a problem if different levels of indirection have mistakenly been used. - Weather Vane
I think this is a useful question for those of us who have used less smart compilers. Decades ago when I first learned C, the (mildly outdated even at the time) stock compiler actually generated warnings for assigning typed pointers to void * variables without casts. That set very many people up for fails. I remember being quite frustrated at one point because I had a function that took a pointer to an array fine, but not a pointer to a pointer. It was this exact issue, and it was masked because the compiler warned about the wrong thing. Using gcc showed my problem and let me fix it. - Ed Grimm

2 Answers

2
votes

The lower version tells you what the problem was in the first one: passing a pointer to the array instead of a pointer to the first element.

Passing a pointer to the array, which has the type int(*)[3]:

test(&test_array, var_1);

Passing a pointer to the first element, which has the type int*:

test(test_array, var_1);   

The code happens to work because the two pointers points to the same address, so the pointer to the array appears to work, but the code is still undefined.

Passing a pointer to the first element is correct, as the array test_array, which has the type int[3] decays to type int* when it is passed to the function.

0
votes

The warnings are shown because the compiler does static analysis on the code and identified a possible cause of bugs.

When using the void pointer the compiler cannot do this static analysis since it does not know what type is used.

If the datatype is known I would always prefer using this type as pointer instead of the void pointer. I would only use the void pointer when it is acceptable that the pointer can point to anything. In the end this is about personal taste and the code guidelines you follow.