在C语言中,从赋值表达式读取属性是否属于未定义行为?
函数参数求值顺序引发的未定义行为问题
问题代码
_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);
问题现象
调用_nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char)应返回一个length为22、buffer有效的结构体,但第一行snprintf计算出的intpd_str1.length结果为14;在GDB中先执行(_nhp_var_str = ...)赋值表达式,再读取_nhp_var_str.length能得到正确值30。
原因分析
这是C语言函数参数求值顺序未指定导致的问题。C标准没有规定函数多个参数的求值顺序,编译器可选择任意顺序处理snprintf的各个参数。在这段代码中,编译器可能先求值第四个参数_nhp_var_str.buffer,再执行第三个参数里的(_nhp_var_str = ...).length赋值操作。此时_nhp_var_str还是赋值前的旧值,导致%.*s格式符使用了错误的长度或无效缓冲区,最终计算出的字符串长度不符合预期。
这种跨参数存在依赖但无明确执行顺序的代码,属于C标准定义的未定义行为范畴——不同编译器、甚至同一编译器不同优化等级下都可能产生不同结果。
解决方案
将赋值操作从函数参数中提取出来单独执行,确保后续代码使用的是更新后的_nhp_var_str值:
_nhp_array_char_t intpd_str1; // 先完成赋值,确保后续snprintf参数使用最新值 _nhp_var_str = _nhp_var_you->to_array_char->_nhp_this_anon(_nhp_var_you->to_array_char); intpd_str1.length = snprintf(NULL, 0, "You're %.*s!", _nhp_var_str.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);
这样强制了赋值操作的执行顺序,避免了参数求值顺序带来的不确定性,保证snprintf使用的是正确的length和buffer。
内容的提问来源于stack exchange,提问作者mike
相关产品推荐
相关产品推荐

