Search code examples
csizeof

C: Unexpected result when cast'ing an array within sizeof()


I had to experience a(nother) - to me - unexpected C behavior, this time with sizeof.

My goal is trying to understand the reasoning behind this behavior and how I'd supposed to solve this. I'm not really interested in alternative solutions as my main goal is understanding what's happening here and why.

I'm having a string defined via the #define-C-preprocessor macro (#define CONST "foobar") and use it in functions like:

senddata(uint8_t * data, uint32_t len).

Since - depending on implementation/architecture, but at least on x86 - char is signed by default, I'm getting a warning about "differ[ence] in signedness" when calling it this way:

senddata(CONST, sizeof(CONST)).

So I'd have to cast it (senddata((uint8_t *)CONST, sizeof(CONST))) on every senddata-invocation.

Since all uses of CONST in my code were actually going to be cast'ed to uint8_t anyway, I figured I will just change the define:

#define CONST "foobar" -> #define CONST ((uint8_t *)"foobar")

and don't have to bother with further casting anymore.

While this indeed removes the warning and everything seems fine, I had to learn the hard way that in those cases sizeof() doesn't actually return the length of the string anymore, but the size of the data type, in this case uint8_t *.

To me this doesn't seem obvious at all.

So my question is 2 folded:

  • 1) How would I do it right in above scenario?
  • 2) Why is it the way it is?
  • 3) How would I have been able to know about this? This is not meant (passive-)aggressively, but rather: with what prior knowledge should I have been able to come to the conclusion that this does not work that way?

Some half-knowledge I picked up somewhere which might play into this but I'm not quite sure what to make out of it: sizeof() is not a normal function but a operator (e.g. sizeof int works without brackets).

Another speculation of mine: "foobar" is a char-array while (char *)"foobar" is a pointer.


Solution

  • You are almost there, the thing you need to keep in mind that, sizeof works on the type of the operand, not the value.

    Quoting C11, chapter §6.5.3.4

    The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

    For example, sizeof ("array") is the same as sizeof (char [6]), because "array" is of type char[6]. Given that the size of a char is defined to be 1, it'll yield a result of 6.

    However, when you use a cast for the operand of the sizeof, it considers that cast as the type as per the above definition. So, something like sizeof ((char*)"array") will be the same as sizeof (char*). Based on your platform, it can yield a value of 4 or 8, size of a pointer (to char).