在C中,读取是否超过了对象未定义的行为?
将整数地址转换为双指针并读取,但整数的大小小于double type,读取操作将读取超过对象大小。我相信这是未定义的行为,但我没有在C标准中找到描述,所以我发布这个问题以寻求答案来确认我的观点在C中,读取是否超过了对象未定义的行为?,c,undefined-behavior,C,Undefined Behavior,将整数地址转换为双指针并读取,但整数的大小小于double type,读取操作将读取超过对象大小。我相信这是未定义的行为,但我没有在C标准中找到描述,所以我发布这个问题以寻求答案来确认我的观点 #include <stdio.h> #include <stdint.h> int main() { int32_t a = 12; double *p = (double*)(&a); printf("%lf\n", *p); retu
#include <stdio.h>
#include <stdint.h>
int main() {
int32_t a = 12;
double *p = (double*)(&a);
printf("%lf\n", *p);
return 0;
}
#包括
#包括
int main(){
int32_t a=12;
双*p=(双*)(&a);
printf(“%lf\n”,*p);
返回0;
}
来自6.5表达式
第7点:
对象的存储值只能由具有以下类型之一的左值表达式访问:76)-与对象的有效类型兼容的类型,
-与对象的有效类型兼容的类型的限定版本,
-与对象的有效类型相对应的有符号或无符号类型,
-一种类型,它是与对象的有效类型的限定版本相对应的有符号或无符号类型,
-在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的成员),或
-字符类型
int
类型的对象使用double
类型的左值表达式访问其地址int
和double
类型无论如何都不兼容,它们不是聚合的,而且double
不是字符类型。取消引用指向int类型对象的double类型的指针(左值表达式)是未定义的行为。此类操作称为严格别名冲突。根据C116.5(“严格别名规则”)这是未定义的行为:
6访问其存储值的对象的有效类型是该对象的声明类型(如果有)。在这种情况下,有效类型是
int32\u t
(这是一个与int
或long
类似的类型相对应的typedef)
7对象的存储值只能由具有以下类型之一的左值表达式访问:-与对象的有效类型兼容的类型,
double
与int32\u t
不兼容,因此当代码访问此处的数据时:*p
,它违反此规则并调用UB
有关详细信息,请参阅。如果使用与“int”类型没有可见关系的左值访问类型为“int”的对象,则该标准不要求编译器的行为可预测。然而,在基本原理中,作者指出,将某些行为分类为未定义的行为是为了让市场决定在质量实施中哪些行为是必要的。一般来说,将指针转换为另一种类型,然后立即使用它执行访问的操作属于高质量编译器支持的操作类别,这些编译器被配置为适合系统编程,但可能不受行为迟钝的编译器的支持 然而,即使忽略了左值类型的问题,该标准也没有对应用程序试图从它不拥有的内存中读取时会发生什么提出任何要求。在这里,行为的选择有时可能是实现质量的问题。这里有五种主要的可能性:
\uuuuu STDC\u ANALYZABLE\uuuuu
的实现
让大多数行为遵守时间法则和因果关系,即使在
该标准不会提出其他要求,超出范围的读数为
被归类为关键的未定义行为,因此应予以考虑
对未明确规定的任何实现都是危险的
顺便说一句,即使代码使用了int[3]
而不是单个int
,在某些平台上也会出现另一个问题:对齐。在某些平台上,某些类型的值只能读写到某些地址,而某些适合较小类型的地址可能不适合较大类型的地址。在int
需要32位对齐而double
需要64位对齐的平台上,给定int-foo[3]
,编译器可以任意放置foo
,以便(double*)foo
将是存储double
的合适地址,或者(double*)(foo+1)
将是一个合适的地方。熟悉实现细节的程序员可能能够确定哪个地址是有效的,并利用它,但是盲目假设foo
的地址是有效的代码可能会