0

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
}
8
  • Does this code actually compile? Anyway, just pass the size you want as an additional parameter to the method, or scan for a null value, or something like that. Commented Dec 9, 2014 at 23:57
  • You cannot pass an array to a function in C. Like, at all. All you can do is passing pointers, like a pointer to an array of 6 char. Though @RobertHarvey mentioned how any sane person deals with it in C. Commented Dec 9, 2014 at 23:58
  • I want 6 to just appear once, so if it needs to be changed, there's only a single place to do that. I could of course define it, but that would be a bit over-verbose. Commented Dec 10, 2014 at 0:07
  • OP, could it be that you actually want to use C++ instead of C? Commented Dec 10, 2014 at 0:17
  • I just want to pass a plain pointer. With the compiler keeping track that it points to 6 elements, not an arbitrary amount. What's wrong with that? If it's impossible, fine, I could happily accept that as an answer. Commented Dec 10, 2014 at 0:19

2 Answers 2

4

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;
}
Sign up to request clarification or add additional context in comments.

8 Comments

There is no point of doing this, if you hardcode the size, then just use that size.
Yes, it doesn't look that useful, but it's a neat trick. I didn't know this was possible.
he wants the function signature to include 6 for style and readability. This is a fine answer
@dragonroot You asked for for a solution that supported "this for style and readability purposes". Now you have another condition to avoid a "solution introduces an additional reference/dereference operation". Suggest updating your post to include that, rather than only in a local comment, or rate answers without that addition.
Interesting example of how to print an array with printf("%.*s\n", (int) sizeof(array), array);
|
2

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.

4 Comments

Just to be clear, I don't want to pass an array by value. I want to pass a pointer to an array of 6 chars, and I want the signature of the function to contain that information. Furthermore, I want this size information to be retrievable within the function from the signature. While I can write void fn( char foo[ 6 ] ), I can't retrieve that 6 from within the body of the function. Btw, I'm writing this comment to you just to have at least one person in this whole thread who understands me. The rest of the crowd doesn't seem to, which makes me sad. Thanks for your participation :)
@dragonroot It is strange that the C language lets you specify foo[6], when it ignores the 6 entirely. I added something in my answer about that. Maybe some language lawyer knows why foo[6] is allowed, when it apparently doesn't mean anything different from foo[].
Exactly. As for the workaround you've mentioned, it adds both additional indirection and additional memory use, while I just want the compiler to give me that value of 6 at compile time :)
"the compiler does pay attention to the sizes you give, except for the first one". That's the issue, for an array, the one and only size is the first one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.