cFs*_*chb 39 c sizeof string-literals language-lawyer mikroc
在微控制器上,为了避免加载之前固件版本的设置,我还存储编译时间,在加载时检查该时间。
\n该微控制器项目是使用MikroElektronika 的“ mikroC PRO for ARM”构建的。
\n为了方便调试,我在PC上用minGW编写了代码,左右检查后,将其放入microC中。
\n使用该检查的代码无法正常工作。经过一晚令人沮丧的调试后,我发现sizeof("...")
在两个平台上产生了不同的值,并因此导致缓冲区溢出。
但现在我不知道这是谁的错。
\n要重新创建问题,请使用以下代码:
\n#define SAVEFILECHECK_COMPILE_DATE __DATE__ " " __TIME__\n\nchar strA[sizeof(SAVEFILECHECK_COMPILE_DATE)];\nchar strB[] = SAVEFILECHECK_COMPILE_DATE;\n\nprintf("sizeof(#def): %d\\n", (int)sizeof(SAVEFILECHECK_COMPILE_DATE));\nprintf("sizeof(strA): %d\\n", (int)sizeof(strA));\nprintf("sizeof(strB): %d\\n", (int)sizeof(strB));\n
Run Code Online (Sandbox Code Playgroud)\n在 MinGW 上它返回(如预期):
\n#define SAVEFILECHECK_COMPILE_DATE __DATE__ " " __TIME__\n\nchar strA[sizeof(SAVEFILECHECK_COMPILE_DATE)];\nchar strB[] = SAVEFILECHECK_COMPILE_DATE;\n\nprintf("sizeof(#def): %d\\n", (int)sizeof(SAVEFILECHECK_COMPILE_DATE));\nprintf("sizeof(strA): %d\\n", (int)sizeof(strA));\nprintf("sizeof(strB): %d\\n", (int)sizeof(strB));\n
Run Code Online (Sandbox Code Playgroud)\n然而,在“mikroC PRO for ARM”上,它返回:
\nsizeof(#def): 21\nsizeof(strA): 21\nsizeof(strB): 21\n
Run Code Online (Sandbox Code Playgroud)\n这种差异导致了缓冲区溢出(覆盖了指针 \xe2\x80\x93 的字节零)。
\n21 是我期望的答案:20 个字符和 \'\\0\' 终止符。
\n这是 C 中“视情况而定”的事情之一,还是违反了sizeof
运算符行为?
Lun*_*din 42
这一切都是100%标准化的。C17 6.10.8.1:
__DATE__
预处理翻译单元的翻译日期:...形式的字符串文字,如果值小于 10,则"Mmm dd yyyy"
第一个字符是空格字符。 ... 预处理翻译单元的翻译时间:形式的字符串文字dd
__TIME__
"hh:mm:ss"
" "
(用于字符串文字连接的空格)= 111 + 8 + 1 + 1 = 21
至于sizeof
,字符串文字是一个数组。每当您将声明的数组传递给 时sizeof
,该数组都不会“衰减”为指向第一个元素的指针,因此sizeof
将报告数组的大小(以字节为单位)。对于字符串文字,这包括 null 终止符,C17 6.4.5:
在翻译阶段 7,值为零的字节或代码被附加到由一个或多个字符串文字产生的每个多字节字符序列。然后,使用多字节字符序列来初始化静态存储持续时间和长度足以包含该序列的数组。对于字符串文字,数组元素的类型为
char
,并使用多字节字符序列的各个字节进行初始化。
(还提到了翻译阶段 6,即字符串文字连接阶段。即字符串文字连接保证在添加空终止之前发生。)
因此,mikroC PRO 似乎不合格/存在缺陷。肯定有很多有问题的嵌入式系统编译器。
chq*_*lie 15
\n\nIs this one of the \'it depends\' things in C or is there a violation of the
\nsizeof
operator behavior?
The behavior is fully defined in the C Standard. Below are the relevant quotes from the C99 published standard, which were identical except for the section numbers in the C90 (ANSI C) version and have not been modified in essence in more recent version up to and including the upcoming C23 version:
\nThe __DATE__
and __TIME__
macros are specified by
\n\n6.10.8 Mandatory macros
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
__DATE__
The date of translation of the preprocessing translation unit: a character string literal of the form "Mmm dd yyyy"
, where the names of the months are the same as those generated by theasctime
function, and the first character ofdd
is a space character if the value is less than10
. If the date of translation is not available, an implementation-defined valid date shall be supplied.__TIME__
"hh:mm:ss"
预处理翻译单元的翻译时间:函数生成的时间形式的字符串文字asctime
。如果翻译时间不可用,则应提供实现定义的有效时间。
由上可知,如果翻译时间可用,则宏SAVEFILECHECK_COMPILE_DATE
expands to 3 string literals for a total of 11+1+8 = 20 characters, hence 21 bytes including the null terminator. If the time of translation is not available, implementation defined valid dates and times must be used, hence the behavior must be the same.
\n\n5.1.1.2 翻译阶段
\n\n
\n- 相邻的字符串文字标记被连接起来。
\n- 分隔标记的空白字符不再重要。每个预处理标记都会转换为一个标记。对生成的标记进行句法和语义分析,并将其翻译为翻译单元。
\n
因此,sizeof
由 3 个相邻字符串文字构成的参数是无关紧要的,所有出现的sizeof
operator in your examples get a single string literal argument in phase 7, then
\n\n6.5.3.4
\nsizeof
操作员4\xc2\xa0\xc2\xa0当
\nsizeof
应用于类型为 、 或 的操作数char
(unsigned char
或其signed char
限定版本)时,结果为1
。当应用于具有数组类型的操作数时,结果是数组中的字节总数。
因此,示例中的所有 3 个输出都必须显示 21 个字节。您在mikroc编译器中发现了一个错误:您应该报告它并为您当前的项目找到解决方法。
\nsup*_*cat 10
sizeof
正如其他人所指出的,字符串文字上的行为早已被标准化为产生一个比由此表示的字符串长度大一的值,而不是可以使用该字符串文字初始化的最小字符数组的大小。话虽如此,如果希望使代码即使与采用后一种解释的编译器兼容,我建议使用类似的表达式,(1-(sizeof "")+(sizeof "stringLiteral of interst"))
这样可以允许代码与古怪的编译器正确运行,但避免牺牲与标准编译器的兼容性。
归档时间: |
|
查看次数: |
5033 次 |
最近记录: |