dragonroot
dragonroot

Reputation: 5821

Is it possible to pass an array of a predefined size to a C function so that its size could be retrieved with `sizeof` in that function?

In the following example, is it possible to declare test() with such a signature so it would print 6? I would like this for style and readability purposes, so that it's clear that the function takes an array of exactly 6 chars, and it actually can get this information with sizeof.

#include <stdio.h>

void test( char foo[ 6 ] )
{
  printf( "%zu\n", sizeof( foo ) ); // Prints 8 as it's a pointer now, but I want 6 as in an array
}

int main()
{
  char foo[ 6 ];
  printf( "%zu\n", sizeof( foo ) ); // Prints 6, which is what I want
  test( foo );
  return 0;
}

So far, the best I could come up with is this:

typedef char Foo[ 6 ];
void test( Foo foo )
{
  printf( "%zu\n", sizeof( Foo ) ); // Works, but it doesn't even use foo, and I want to get the size information from foo! What if I change the signature of the function later? I would have to update this line too, which is something I'd like to avoid
}

Upvotes: 0

Views: 109

Answers (2)

yellowantphil
yellowantphil

Reputation: 1493

Not without some acrobatics.

There are ways to make it work, either with global variables as in your question, or the solutions proposed by Kay. But the C language does not pass entire arrays by value as function arguments. Your test function only receives a pointer to a char, and the compiler will not tell you what size of array the pointer might point to.

Some other languages, like C++, handle this sort of thing for you. But in C, you just have to track the size yourself, one way or another. A common way is to add another argument to your function, where you pass in the size of your array.

In the function prototype you gave:

void test( char foo[ 6 ] )

I think that the compiler unfortunately just ignores the 6, although you could argue that that doesn't make much sense. For a multi-dimensional array, the compiler does pay attention to the sizes you give, except for the first one, so foo[][6] works, and is necessary to tell the compiler where each row of your array ends. (See this question.)

Yet another workaround would to use a structure like this:

struct array {
    char *a;   // pointer to your real array
    size_t s;  // how many elements your array has
};

You could pass one of those structures to your function, and then read the size out of it.

Upvotes: 2

Kijewski
Kijewski

Reputation: 26022

Yes, it is possible:

#include <stdio.h>

void test(char (*foo)[6]) // "declare foo as pointer to array 6 of char" 
{
  printf("%zu\n", sizeof(*foo)); // mind the asterisk
}

int main(void)
{
  char foo[6];
  test(&foo); // mind the ampersand
  return 0;
}

Compare cdecl.org ("C gibberish ↔ English") for


Another option is wrapping the array. But if you don't like referencing/dereferencing, then this solution with an addition member access probably is not what you are looking for, either:

#include <stdio.h>

typedef struct
{
  char data[6];
} char_6_array_t;

void test(char_6_array_t foo)
{
  // prints "6: abcdef"
  printf("%zu: %.*s\n", sizeof(foo.data), (int) sizeof(foo.data), foo.data);
}

int main(void)
{
  char_6_array_t foo = { {"abcdef"} };

  // Depending on the ABI, this prints 6, 8, or possibly 16:
  printf("%zu\n", sizeof(foo));

  test(foo);
  return 0;
}

Upvotes: 4

Related Questions