我对这两个陈述有一个理论问题:
假设p
一个指向 Integer 和a
Integer 的指针:
一)if(p==a){.....}
或if(p>a)
..
b) p=a
;
它们都是非法的并且b
特别危险,但是标准 C 是如何看待它们的呢?
阅读标准,我没有发现它们是否是错误、未定义的行为、未指定的行为、违反约束,其中一个是否合法。
查看无数类似的问题,我还没有找到解决方案。
都是非法的。为了进行比较,双方都可以转换为通用类型,对于赋值,右侧必须可以转换为左侧的类型,并且:
涉及指针的转换,除了 6.5.16.1 的约束允许的情况外,应通过显式转换来指定。
( 6.5.4 , 3; 6.5.16.1 描述了空指针常量、void
指针和_Bool
赋值情况下的一些例外情况。)
当您添加显式强制转换以将指针转换为整数时,程序再次变为有效,您将从比较中获得布尔值。结果取决于实现。一定要uintptr_t
在以整数形式存储指针时使用。
C11 (n1570) §6.5.8 [关系运算符] / 2:
约束
应满足下列条件之一:
- 两个操作数都有实型;或者
- 两个操作数都是指向兼容对象类型的合格或不合格版本的指针。
(实数类型是指整数类型、枚举、实数浮点类型和char
(§6.2.5/17))
§6.5.9 [等式运算符]
约束
应满足下列条件之一:
- 两个操作数都有算术类型;
- 两个操作数都是指向兼容类型的合格或不合格版本的指针;
- 一个操作数是指向对象类型的指针,另一个是指向合格或不合格版本的指针
void
;或者- 一个操作数是指针,另一个是空指针常量。
§6.5.16.1 [简单赋值] / 1:
约束
应满足下列条件之一:
- 左操作数具有原子、合格或不合格算术类型,右操作数具有算术类型;
- 左操作数具有与右操作数兼容的结构或联合类型的原子、限定或非限定版本;
- 左操作数具有原子、限定或非限定指针类型,并且(考虑到左操作数在左值转换后将具有的类型)两个操作数都是 指向兼容类型的限定或非限定版本的指针,并且左侧指向的类型具有所有右边指向的类型的限定符;
- 左操作数具有原子、限定或非限定指针类型,并且(考虑到左操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向限定或非限定版本的 指针
void
, left 指向的类型具有 right 指向的类型的所有限定符;- 左边的操作数是一个原子的、合格的或不合格的指针,右边是一个空 指针常量;或者左操作数的类型为 atomic、qualified 或 unqualified
_Bool
,而右操作数是 指针。
基本上,所有 3 个表达式都违反了表达式中设置的约束。
违反约束是什么意思?错误?但是没有地方说违反约束会导致翻译失败。C 标准似乎不是很清楚,但最接近的解释是:
§4 [一致性] / 2:
如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。
但这谈到了限制之外;和§5.1.1.3 [诊断] / 1:
如果预处理翻译单元或翻译单元包含违反任何语法规则或约束的行为,则符合的实现应产生至少一个诊断消息(以实现定义的方式标识),即使该行为也明确指定为未定义或实现-定义。在其他情况下不需要生成诊断消息。
所以编译器至少需要产生一条消息(正如我们在 gcc 中看到的那样),但没有说他们在那之后应该做什么。
本段后面的例子提到
例子
实现应为翻译单元发出诊断:
char i; int i;
因为在本国际标准中的措辞将构造的行为描述为约束错误和导致未定义行为的情况下,应诊断约束错误。
和 §6.7 [Declarations] / 3 没有明确提到违反约束将导致未定义的行为。
因此,我推断您的 3 个表达式都是未定义的行为,并伴有诊断消息。
a) 和 b) 都是违反约束的。 C99、第 6.5.8 节、第 6.5.9 节和第 6.5.16.1 节。
我不知道我是否真的在回答你的问题,但这里是。关于a),你有一个比较,所以你基本上说的是“指针是否具有内存地址a?”。在 b) 中,您将值 a 分配给指针,这意味着您说它将指向内存地址“a”。这里有一些提示:
p=&a
您的指针现在指向整数 a 的内存地址。
*p=a
指针指向的值取 a 的值。
p=a
您的指针现在指向内存值 a。
希望它有所帮助!