mik*_*ike 0 c undefined-behavior
我有以下代码片段:
_nhp_array_char_t intpd_str1;
intpd_str1.length = snprintf(NULL, 0, "You\'re %.*s!", (_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length, _nhp_var_str.buffer);
intpd_str1.buffer = _nhp_malloc(intpd_str1.length + 1);
intpd_str1.responsible_destroyer = NULL;
snprintf(intpd_str1.buffer, intpd_str1.length + 1, "You\'re %.*s!", _nhp_var_str.length, _nhp_var_str.buffer);
Run Code Online (Sandbox Code Playgroud)
调用_nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)应该并且确实返回一个带有length22 的结构以及 的有效值buffer。
然而,该表达式的intpd_str1.length = snprintf...计算结果为 14。然而,在 GDB 中,预先运行赋值表达式,然后读取_nhp_var_str.length返回正确的值 30。
我怀疑一定存在某种形式的未定义行为,尽管我还无法确认这一点,即使在搜索谷歌和SO之后也是如此。我认为,出于某种原因,在评估 时(_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length,它决定生成 的结果_nhp_var_str.length而不为 赋值_nhp_var_str。
仅供参考,代码看起来很混乱,因为它是经过转译的;就编码风格而言,我无能为力来实际改变它。
函数调用参数的求值是无序的。在 中snprintf(NULL, 0, "You\\'re %.*s!", (_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length, _nhp_var_str.buffer);,第四个和第五个参数是:
(_nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)).length, 和_nhp_var_str.buffer。第四个参数修改 的值_nhp_var_str(作为赋值的副作用),包括其buffer成员,第五个参数使用 的值_nhp_var_str.buffer。这违反了 C 2018 6.5 2:
\n\n如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是无序的,则行为是未定义的\xe2\x80\xa6
\n
请注意,所讨论的标量对象是_nhp_var_str.buffer,我认为它是一个指针,而不是整个_nhp_var_str结构。(结构是聚合,而不是标量。)
代码的行为基本上不是由 C 标准定义的。即使我们忽略 6.5 2,C 实现也可能会在计算第四个参数之前计算第五个参数,这会导致使用值_nhp_var_str.buffer第四个参数中的赋值设置之前的值。所以转译器的输出被破坏了;转译器有缺陷。要么必须修复它,要么必须在转译器生成代码后对其进行更正。