在微控制器上,为了避免从以前的固件版本加载设置,我还存储编译时间,在加载时检查。
微控制器项目是使用 MikroElektronika 的 'mikroC PRO for ARM' 构建的。
为了更容易调试,我在 PC 上用 minGW 编写了代码,左右检查后将其放入 microC 中。
使用该检查的代码无法正常工作。经过一晚令人沮丧的调试后,我发现 sizeof("...") 在两个平台上返回不同的值,并导致缓冲区溢出成为罪魁祸首。
但现在我不知道是谁的错。
要重新解决问题,请使用以下代码:
#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));
在 MinGW 上它返回(如预期):
sizeof(#def): 21
sizeof(strA): 21
sizeof(strB): 21
在“mikroC PRO for ARM”上,它返回:
sizeof(#def): 20
sizeof(strA): 20
sizeof(strB): 21
这种差异导致了缓冲区溢出。 (覆盖指针的字节零,哎呀!) 21 是我期望的答案,20 个字符和 ' ' 终止符。 这是 C 中“视情况而定”的事情之一,还是 sizeof 运算符的行为遭到破坏?
这一切都是100%标准化的。 C17 6.10.8.1:
预处理翻译单元的翻译日期:__DATE__
"Mmm dd yyyy"
形式的字符串文字 ...
预处理翻译单元的翻译时间:字符串文字 形式__TIME__
"hh:mm:ss"
" "
(用于字符串文字连接的空格)= 111 + 8 + 1 + 1 = 21
至于
sizeof
,字符串文字是一个数组。每当您将声明的数组传递给 sizeof
时,该数组都不会“衰减”为指向第一个元素的指针,因此 sizeof
将报告数组的大小(以字节为单位)。对于字符串文字,这包括 null 终止符。
因此,mikroC PRO 似乎不合格/存在缺陷。肯定有很多有问题的嵌入式系统编译器。
#include <stdio.h>
int main(){
printf("%zu\n", sizeof("aa"));
}
有趣的是,在这种情况下,
"aa"
并没有衰减为指针,而是充当字符数组。由于数组有 3 个元素(包括零终止符),因此输出为 3。
这定义了字符串(字符数组)
#include <stdio.h>
#define SAVEFILECHECK_COMPILE_DATE __DATE__ " " __TIME__
int main(){
printf("%zu\n", sizeof(SAVEFILECHECK_COMPILE_DATE));
}
每次编译的结果都不一样,因为
__DATE__
和__TIME__
。
我目前的结果是21,但可能会改变。
对于 C++ 也同样有效。