GCC报的‘sequence point’未定义行为警告在C语言中是否有效?
关于两段C代码的未定义行为分析
代码1:p = buf + sprintf(p=buf, "%d", 123);
这段代码的行为是定义良好的,不属于未定义行为。
C标准明确规定,函数调用存在两处序列点:一是所有参数求值完成后、函数体执行前;二是函数返回后、调用者表达式继续执行前。在这段代码中:
- 先完成
sprintf参数p=buf的求值(包含将p修改为buf的副作用),随后到达函数调用的序列点; - 执行
sprintf函数并返回3,之后到达函数调用结束的序列点; - 最后计算
buf + 3并将结果赋值给p。
两次对p的修改被函数调用的序列点明确分隔,操作顺序完全确定,符合C标准要求。gcc的警告属于保守性提示,实际不存在未定义行为。
代码2:p += sprintf(p=buf, "%d", 123);
这段代码属于未定义行为,与gcc的警告一致。
p += x在C中等价于p = p + x,展开后代码变为p = p + sprintf(p=buf, "%d", 123);。此时右边表达式包含两个关键操作:
- 读取
p的当前值(用于计算p + ...); - 在
sprintf参数中修改p的值(p=buf)。
根据C标准,赋值运算符的左右操作数求值顺序未指定,且右边表达式内部的子表达式求值顺序也未指定——编译器可选择先读取p的旧值再修改p,或先修改p再读取新值,两种情况会产生完全不同的结果。由于这两个操作(读取和修改p)之间没有序列点分隔,属于未排序操作,因此触发未定义行为。
内容的提问来源于stack exchange,提问作者raygard
相关产品推荐
相关产品推荐

