问题描述
在C89标准中,我找到以下部分:
3.2.2.1 L值和功能指示符
除非它是sizeof运算符、一元&;运算符、++运算符、--运算符或的左操作数的操作数。运算符或赋值运算符,则不具有数组类型的左值将转换为存储在指定对象中的值(不再是左值)。如果左值具有限定类型,则该值具有左值类型的非限定版本;否则,该值具有左值类型。如果左值的类型不完整并且没有数组类型,则行为未定义。如果我没有读错,它允许我们创建lvalue
并对其应用一些运算符,这将在运行时编译并可能导致未定义的行为。
问题是,我想不出一个类型不完整的左值可以通过编译器的语义检查并触发undefined behavior
的例子。
假设左值为
lValue是指定对象的表达式(具有对象类型或不完整类型,而不是空)。
且不完整类型为
类型分为对象类型(描述对象的类型)、函数类型(描述函数的类型)和不完整类型(描述对象但缺少确定其大小所需的信息的类型)。
我尝试的失败程序:
struct i_am_incomplete;
int main(void)
{
struct i_am_incomplete *p;
*(p + 1);
return 0;
}
并收到以下错误:
error: arithmetic on a pointer to an incomplete type 'struct i_am_incomplete'
*(p + 1);
~ ^
有人能想出这方面的例子吗?左值类型不完整的";示例,可以通过编译器的语义检查并触发undefined behavior
。
更新:
正如@algid在答案中所说,我误解了undefined behavior
,它包含了compile error
作为选项。
也许我是在吹毛求疵,我仍然想知道这里更喜欢undefined behavior
而不是disallowing an lvalue to have an incomplete type
的潜在动机。
推荐答案
某些生成系统的设计方式可能允许以下代码:
extern struct foo x;
extern use_foo(struct foo x); // Pass by value
...
use_foo(x);
在编译器不必知道或关心的情况下成功处理
关于struct foo的实际表示[例如,一些系统可能会通过让调用者传递对象的地址并要求被调用的函数复制(如果它要修改它)来处理按值传递)。
这样的工具在可以支持它的系统上可能很有用,我认为标准的作者不想暗示使用该功能的代码是"坏的",但他们也不想强制要求所有的C实现都支持这样的功能。将行为设置为未定义将允许实现在实际情况下支持它,而不需要它们这样做。