Search code examples
arrayscpointersimplicit-conversiongcc-warning

Passing array in a c function using address operator gives a warning


I was trying to pass an array to a method. I tried following ways:

  1. func2(ARRAY_NAME, length) => WORKS, no warning
  2. func2(&ARRAY_NAME[0], length) => WORKS, no warning
  3. func2(&ARRAY_NAME, length) => WORKS, but WITH WARNING

I dont understand why the last one (#3) gives warning. &ARRAY_NAME works without warnings in memset, memcpy etc. Why its a problem in custom method?

WARNING message:

functionTest.c:35:11: warning: passing argument 1 of ‘func2’ from incompatible pointer type [-Wincompatible-pointer-types]
   35 |     func2(&temp, ARRAY_SIZE);
      |           ^~~~~
      |           |
      |           unsigned char (*)[200]
functionTest.c:8:27: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[200]’
    8 | void func2(unsigned char* buf, int length)

CODE

#include <stdio.h>
#include <stdint.h>
#include <string.h>


#define ARRAY_SIZE 200

void func2(unsigned char* buf, int length) 
{
    // Change data of any index
    buf[0] = 100;
    buf[10] = 200;
}

void func1()
{
    unsigned char temp[ARRAY_SIZE]; 
    // Initialize
    memset(temp, 0, sizeof(temp));

    for(int i = 0; i < ARRAY_SIZE; i++)
    {
        printf("\t%d", temp[i]);
    }

    printf("\n-----------------------------------------------\n");

    printf("Address : %p\n", &temp);
    printf("Address of 0th index : %p\n", &temp[0]);
    
    printf("\n-----------------------------------------------\n");

    // Pass array in func2  

    func2(&temp, ARRAY_SIZE); // WARNING

    func2(&temp[0], ARRAY_SIZE); // NO WARNING

    for(int i = 0; i < ARRAY_SIZE; i++)
    {
        printf("\t%d", temp[i]);
    }

    printf("\n-----------------------------------------------\n");
}

int main()
{
    func1();
    return 0;
}

Solution

  • As it is clear written in the error message

    functionTest.c:8:27: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[200]’
        8 | void func2(unsigned char* buf, int length)
    

    the function expects a pointer of the type unsigned char * but the argument expression &temp has the type unsigned char ( * )[200] and there is no implicit conversion from one pointer type to another though values of the pointers are the same: the address of the extent of memory occupied by the array.

    As for the functions memset and memcpy then they deal with pointers of the type void *. For example the function memset has the following declaration

    void *memset(void *s, int c, size_t n);
    

    And a pointer to object of other type can be implicitly converted to pointer of the type void *.

    From the C Standard (6.3.2.3 Pointers)

    1 A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.