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