-1

I'm currently coding some encryption algorithm, and I am facing a GCC compilation error I can't understand. Here is the problem :

In my int main(void) function I got :

uint32_t block[2];
memset(block, 0x0, sizeof(block));
printf("%ld \n", sizeof(block));

Which looks okay for GCC.

Then, I pass this uint32_t array named block to a function :

void readOneBlockFromFile(int fd, uint32_t block[2]){
  if(fd == -1){
    perror("fd");
    errno = EIO;
    exit(errno);
  }
  int nb_bytes_read = 0;
  while(1){
    memset(block, 0x0, sizeof(block));
    nb_bytes_read = read(fd, block, sizeof(block));
    if(nb_bytes_read == -1){
      perror("read");
      exit(errno);
    }
    if(nb_bytes_read == 0){
      break; //EOF
    }
  }
}

And here I get some GCC warnings :

SPN.c: In function ‘readOneBlockFromFile’:
SPN.c:46:30: warning: ‘sizeof’ on array function parameter ‘block’ will return size of ‘uint32_t * {aka unsigned int *}’ [-Wsizeof-array-argument]
     memset(block, 0x0, sizeof(block));
                              ^
SPN.c:38:44: note: declared here
 void readOneBlockFromFile(int fd, uint32_t block[2]){
                                            ^~~~~
SPN.c:47:43: warning: ‘sizeof’ on array function parameter ‘block’ will return size of ‘uint32_t * {aka unsigned int *}’ [-Wsizeof-array-argument]
     nb_bytes_read = read(fd, block, sizeof(block));
                                           ^
SPN.c:38:44: note: declared here
 void readOneBlockFromFile(int fd, uint32_t block[2]){
                                            ^~~~~

So my GCC is giving me warning when I'm using block without using block[0] or *block.

I can't figure out why GCC gives me warning for this, as I can do the same stuff without any problem in main.

kfx
  • 8,136
  • 3
  • 28
  • 52
Nark
  • 454
  • 1
  • 7
  • 18

2 Answers2

3

In your function heading

void readOneBlockFromFile(int fd, uint32_t block[2])

you declare block to be an array of size 2. However, in C an array is always pased as a pointer to its first element. Therefore sizeof will return the size of the pointer, not of the array.

(In essence, declaring the size of an array you pass helps the compiler check your code, whether you pass the right arguments. In multi-demensional arrays the compiler lets you use [][] indexing. Without declaring the size of the array passed, that would not be possible.)

You further seem to know already what size the array is, so pass that to read, e.g. sizeof(uint32_t [2]).


In my opinion a more usefull interface is:
int readOneBlockFromFile(int fd, void *block, int size)
{
     int nb_bytes_read = read(fd, block, size);
     //...
     return nb_bytes_read;
}
int example(void)
{
    uint32_t block[2];
    if (readOneBlockFromFile(1,block,sizeof(block))==0) {
        // EOF
    }
}
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
3

To support Paul Ogilive's awesome answer:

From C11 standard 6.3.2.1

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

This is the exhaustive rule - in case when array is converted into pointer and when it is not. Here it is also a case where array is converted into pointer when it is passed to a function.

-Emphasis mine

Community
  • 1
  • 1
user2736738
  • 30,591
  • 5
  • 42
  • 56