Home > OS >  Passing array in a c function using address operator gives a warning
Passing array in a c function using address operator gives a warning

Time:05-11

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;
}

CodePudding user response:

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.

CodePudding user response:

func2 is declared to have a first parameter of type unsigned char *, so it should be passed a pointer to a type compatible with unsigned char or a pointer to void, which will be automatically converted to unsigned char *.

With func2(temp, ARRAY_SIZE), the array temp is automatically converted to a pointer to its first element. This pointer is an unsigned char *, so it satisfies the requirements.

With func2(&temp[0], ARRAY_SIZE), temp[0] is an unsigned char, so &temp[0] is a pointer to an unsigned char. This satisfies the requirements.

With func2(&temp, ARRAY_SIZE), &temp is a pointer to an array of 200 elements of unsigned char. It points to the same place as &temp[0], bit its type is different. It is a pointer to an array, not a pointer to unsigned char or to a compatible type nor a pointer to void. So it does not satisfy the requirements, and the compiler complains.

Pointers to unsigned char and pointers to arrays are different. If the type of pu is unsigned char * and the type of pa is unsigned char (*)[200] (a pointer to an array of 200 unsigned char), then adding 1 to pu, as in pu 1, produces a pointer to the next unsigned char after pu, but adding 1 to pa produces a pointer to the next array after pa. In other words, pu 1 points to the next byte in memory, but pa 1 points 200 bytes further along in memory.

One purpose of C’s type system is to help avoid errors. When a non-matching type is passed to a function, the programmer may be expected some behavior other than what the language defines. So the compiler issues a diagnostic message.

With memset, its first parameter is declared to be void *. void is an incomplete type; it acts as a placeholder for other types. memset is designed to work on the bytes of any object, so it accepts a pointer to any object type. When any pointer to an object type is passed for a void * parameter, it is automatically converted to void *, without any diagnostic message.

  • Related