-1

EDIT: while someone thought this question is the same as the one they posted a link to. It is a very different question.

consider the following:

#define HUNDRED 100
typedef WCHAR BUFFER_SPACE[HUNDRED]; 

the type BUFFER_SPACE is an array with a size of 200 bytes (assume UTF16)

In most cases, declaring a variable such as:

BUFFER_SPACE abuffer         = { 0 };

wprintf(L"sizeof abuffer        : %zd\n", sizeof(abuffer));

will result in wprintf outputting 200 (as expected.)

Now, consider the following simple sample program:

#include "stdafx.h"
#include <Windows.h>
#include <WinNt.h>

#define HUNDRED 100
typedef WCHAR BUFFER_SPACE[HUNDRED]; 

void Function(BUFFER_SPACE abuffer)
{
  BUFFER_SPACE anotherbuffer = { 0 };

  wprintf(L"sizeof  abuffer      : %zd\n", sizeof(abuffer));         // 8
  wprintf(L"sizeof *abuffer      : %zd\n", sizeof(*abuffer));        // 2
  wprintf(L"sizeof anotherbuffer : %zd\n", sizeof(anotherbuffer));   // 200

  // a highly undesirable solution is to apply sizeof to the type but, if the
  // type of the parameter changes, the programmer has to be aware that the
  // original/old type is being used in sizeof() someplace else in the
  // function/program

  wprintf(L"sizeof BUFFER_SPACE  : %zd\n", sizeof(BUFFER_SPACE));  // 200

  getchar();
}

int main()
{
  BUFFER_SPACE abuffer         = { 0 };

  WCHAR anotherbuffer[HUNDRED] = { 0 };

  wprintf(L"sizeof abuffer        : %zd\n", sizeof(abuffer));
  wprintf(L"sizeof anotherbuffer  : %zd\n", sizeof(anotherbuffer));
  wprintf(L"\n");

  Function(abuffer);

  return 0;
}

I wanted to get the entire size of the buffer parameter in the function. Using VC++ and compiling for 64 bit,

sizeof(abuffer) is 8 which makes sense since it is a pointer to the array

sizeof(*abuffer) is 2 which I consider rather questionable but, it is not something I want to debate.

sizeof(BUFFER_SPACE) is 200 as it should be.

My question is: Is there a way to get the value of 200 from the parameter (abuffer in this case) or is using the type the only way to get it ?

ScienceAmateur
  • 521
  • 4
  • 11
  • What is `sizeof (WCHAR)`?? If `abuffer` is a pointer to `WCHAR`, then what is `*buffer`? You may want to review [Is it a good idea to **typedef** pointers?](http://stackoverflow.com/questions/750178/is-it-a-good-idea-to-typedef-pointers). – David C. Rankin May 16 '18 at 05:01
  • 2
    Don’t typedef arrays, it’ll be really confusing. – Ry- May 16 '18 at 05:12
  • 1
    At an abstract level, your question is really duplicate of [this one](https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array), even if you believe it is not – Basile Starynkevitch May 16 '18 at 13:57
  • @basile: obviously you don't understand why the question is different. – ScienceAmateur May 16 '18 at 14:06
  • Then you need to edit it even more, explaining what you really want to ask with some [MCVE] – Basile Starynkevitch May 16 '18 at 14:07
  • Put the buffer in a structure `typedef struct { WCHAR buf[HUNDRED]; } BUFFER_SPACE;` – chux - Reinstate Monica May 16 '18 at 15:04
  • 1
    This post would be worth re-opening if it clearly included the key ideas from OP's various comments. – chux - Reinstate Monica May 16 '18 at 15:05
  • 1
    @chux: your thought of using a struct is a good one. I'll give that a try. – ScienceAmateur May 16 '18 at 15:10
  • In what way is this *any* different to its duplicate? AFAICS, it's exactly the same question, namely *"Is there a way to determine an array's size in a function which has been passed the array as a pointer?"* (and the answer is, "No"). If there's some difference, you need to be explicit as to what the difference is, instead of merely asserting so as if it were fact! – Toby Speight May 16 '18 at 15:51
  • P.S. the correct header for `wprintf()` is `` - using those non-standard headers severely limits your audience for no good reason. – Toby Speight May 16 '18 at 15:53
  • @chux: I wish you had offered that comment as the solution. I would have given you the checkmark as making a struct does allow getting the correct size. I used a struct and passed the parameter by reference which eliminated the level of indirection involved with a pointer to the struct. I also checked the code the compiler generates and it is beautiful. :-) thank you. And for those who think this question is a duplicate, a struct, unlike for this question, would not give the asker the answer he was looking for. – ScienceAmateur May 17 '18 at 04:17

2 Answers2

2

Let us start by looking at how arrays are passed to functions -

Quoting C11, chapter §6.7.6.3p7

A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. ...

This means the prototype of your function effectively becomes -

void Function(WCHAR *abuffer);

In the body of this function, the compiler doesn't have the type information any more. It could be WCHAR[100], WCHAR[200] or even WCHAR[].

I think you already understand why sizeof(abuffer) is 8 -- because it is a pointer.

Now coming to sizeof(*abuffer). The type of abuffer is WCHAR*, so the type of *abuffer will be WCHAR and hence sizeof(*abuffer) == sizeof(WCHAR) == 2.

To answer your main question, is there a way for the function to know the size of the buffer, there are 2 ways -

  1. You pass along the information as a second parameter. But this is not required, since the size will always be sizeof(BUFFER_SPACE).
  2. You pass a pointer to BUFFER_SPACE instead of BUFFER_SPACE. You can change your prototype as -

    void Function(BUFFER_SPACE *abuffer);
    

    and use *abuffer instead of abuffer everywhere. sizeof(*abuffer) will now also return 200, because the type information is rightly preserved.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • thank you. I didn't initially want to declare the parameter as a pointer but, declaring it as a pointer enables getting the size of the parameter using sizeof(*parameter) which meets the goal of using the variable to obtain the size. – ScienceAmateur May 16 '18 at 06:11
  • @ScienceAmateur. that adds an extra level of indirection to your code everywhere (although most compilers should optimize that). There is no real reason to define it as a pointer. The size information is always going to be fixed. Why don't you just use the type to get the size? – Ajay Brahmakshatriya May 16 '18 at 06:30
  • @ScienceAmateur I say this because the fact is that the `sizeof` always comes from the type. It is always resolved during compile time (expect for some cases like VLAs). Meaning the compiler would only substitute `sizeof(*abuffer)` with `200`. It won't depend on what actually is being passed to the function. – Ajay Brahmakshatriya May 16 '18 at 06:32
  • I don't want to use the type because if the parameter type were to change, it would require the programmer to inspect the code to find every place where sizeof is used to get the size of the type and update the code to use the new type. I'll take the level of indirection over code that is inherently fragile and prone to errors during maintenance. – ScienceAmateur May 16 '18 at 14:09
2

To complete the answer by Ajay Brahmakshatriya: in your particular case, you know the size (actually the dimension) of the array, and you could use the preprocessor constant HUNDRED.

But in general (and notably for pointers to heap-allocated arrays) there is no automatic way to get their size, and you should adopt some convention regarding array sizes. A very usual one is to pass the dimension of the array as another parameter to functions. A typical example is the fwrite standard function, or the qsort one, or the snprintf.

You could also consider using structures with flexible array members, with the convention that some fixed field gives the size of that flexible array member.

Then you could think in terms of some abstract data type. I gave a simple Matrix example here. But you still need conventions.

Notice that C is such a low-level language that coding conventions are really important (in particular when you deal with pointers to heap allocated -malloc-ed or calloc-ed- data: you should define and document some convention explaining who and how these pointers should be free-d, and what is the size of the pointed data).

Remember than in C arrays decay into pointers (e.g. when you pass them as parameters, like to your Function), and the sizeof some pointer is always fixed (on my x86-64 Linux system it is always 8) and does not depend of the pointed memory region (and of it allocated size, if any).

is there a way to get the value of 200 from the parameter

No, not in general. You need conventions to deal with that. Very often you pass the dimension as some additional parameter (even your main should have both an argc & the argv, for example). Sometimes it is known differently (thru some field in some structure, some global variable, etc...).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547