clanguage-lawyersizeofstring-literalsmikroc

What is the correct output of sizeof("string")?


On a microcontroller, in order to avoid loading settings from a previous firmware build, I also store the compilation time, which is checked at loading.

The microcontroller project is build with 'mikroC PRO for ARM' from MikroElektronika.

Being easier to debug, I programmed the code with minGW on my PC and, after checking it left and right put, it into microC.

The code using that check failed to work properly. After an evening of frustrating debugging I, found sizeof("...") yielding different values on the two platforms and causing a buffer overflow as a consequence.

But now I don't know whose fault is it.

To re-create the problem, use following code:

#define SAVEFILECHECK_COMPILE_DATE __DATE__ " " __TIME__

char strA[sizeof(SAVEFILECHECK_COMPILE_DATE)];
char strB[] = SAVEFILECHECK_COMPILE_DATE;

printf("sizeof(#def): %d\n", (int)sizeof(SAVEFILECHECK_COMPILE_DATE));
printf("sizeof(strA): %d\n", (int)sizeof(strA));
printf("sizeof(strB): %d\n", (int)sizeof(strB));

On MinGW it returns (as expected):

sizeof(#def): 21
sizeof(strA): 21
sizeof(strB): 21

However, on 'mikroC PRO for ARM' it returns:

sizeof(#def): 20
sizeof(strA): 20
sizeof(strB): 21

This difference caused a buffer overflow down the line (overwriting byte zero of a pointer – ouch).

21 is the answer I expect: 20 chars and the '\0' terminator.

Is this one of the 'it depends' things in C or is there a violation of the sizeof operator behavior?


Solution

  • This is all 100% standardized. C17 6.10.8.1:

    __DATE__ The date of translation of the preprocessing translation unit: a character string literal of the form "Mmm dd yyyy" ... and the first character of dd is a space character if the value is less than 10.
    ...
    __TIME__ The time of translation of the preprocessing translation unit: a character string literal of the form "hh:mm:ss"

    11 + 8 + 1 + 1 = 21

    As for sizeof, a string literal is an array. Whenever you pass a declared array to sizeof, the array does not "decay" into a pointer to the first element, so sizeof will report the size of the array in bytes. In case of string literals, this includes the null termination, C17 6.4.5:

    In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence.

    (Translation phase 6 is also mentioned, which is the string literal concatenation phase. I.e string literal concatenation is guaranteed to happen before null termination is added.)

    So it would appear that mikroC PRO is non-conforming/bugged. There's lots of questionable embedded systems compilers out there for sure.