为什么在C中允许以下int * arr []赋值?

时间:2018-09-20 01:28:56

标签: c++ c arrays

我试图在C和C ++中都输入:

int* arr[3]={1,2,3}; 

C取消引用数组时,C不报告错误并输出1,而C ++报告了分配给int * []的错误类型的错误,这是我所期望的。为什么C允许这样做?

3 个答案:

答案 0 :(得分:3)

您的声明用于初始化为int *的{​​{1}}数组,这在两种编程语言中都有些可疑。在C语言中,发生的事情是从每个{1,2,3}值到一个int值的转换,并且在that conversion周围有很多实现定义和未定义的行为。系统的不确定行为很可能与您的期望相关,并且不清楚您的期望是什么,因此我无法提出更好的选择。直接回答问题

  

为什么C允许这样做?

标准C不允许不允许禁止,因为标准C不能定义。有时,我们留下未定义的内容,以留出以后允许 (按实现)的自由...

我看到一些违反对齐要求的行为最有可能在典型的x86 / 64配置上导致未定义的行为,最有可能与编译时的警告或错误消息(取决于配置)相对应。在某些DSP上,这可能是有效的结构,因此您不会看到警告或错误消息,但是请注意,它不是可移植的C代码。

有点像我们的有符号整数溢出通常用int *包装,以及我们通常如何使用int fubar = INT_MAX; fubar++;进行图钉固定。行为也在那里未定义,但是我们有一些通用规范来解释我们将要看到的常见现象。而不是期望崩溃,我们期望其他一些行为。我们可以更改未定义的行为以适应我们的要求,这取决于我们是调试还是发布。例如,通过使用某些内核向导或类似方法将程序的地址空间映射到以union开始,我们可以在x86 / 64配置上将此构造转换为 function (无论什么意思)。但是,当我们为x86 / 64启用对齐检查时,我们将再次看到崩溃。同样,我们可以启用整数溢出和未初始化变量的陷阱。

无论如何,这都是不可移植且非C语言的。如果您针对给定的体系结构,实现或构建配置有明确的 allowing 手册,则该手册 allowed (相对于C标准)。否则,该代码将以警告的形式处理一些红色标记。

答案 1 :(得分:3)

  

C取消引用数组时,C不报告错误并输出1,而C ++报告了分配给int * []的错误类型的错误,这是我所期望的。为什么C允许这样做?

C 不允许。尽管您的C编译器不符合C语言,但您的C编译器无需接受任何评论即可接受它。很有可能您可以通过打开适当的警告选项来说服C编译器警告该初始化。

您的初始化程序提供int类型的值来初始化int *类型的数组元素。 C确实允许将整数转换为指针,并且将指针转换为整数,但是这些都不属于标准所说的在对象初始化期间自动执行的转换。要符合标准(C99或更高版本),必须进行显式强制转换:

int *arr[3] = { (int *) 1, (int *) 2, (int *) 3 };

C的历史在很早以前就已经标准化,但是,早期的C编译器通常接受这种隐式转换。仍然有大量依赖它们的代码。因此,一些现代的C编译器不使用强制转换就可以接受此类转换。即使实际上该标准要求发出诊断信息,其中一些甚至默认情况下也默默地这样做。

围绕从此类转换获得的指针的含义以及取消引用的指针的效果,还有许多其他问题。 C本身未指定。

答案 2 :(得分:2)

首先,您真的是说:

int arr[3] = { 1, 2, 3 };

C对其强制转换规则不太严格,因此C可以通过创建指向整数的指针数组来确定,指针指向内存地址:0x00000001、0x00000002和0x00000003。

在打开警告的情况下,GCC(C模式下为7.3.0)会说:

pointers.c:2:17: warning: initialization makes pointer from integer without a cast
int *arr[3] = { 1, 2, 3 };
                ^

但是,C ++不能使用它:

pointers.cpp:2:25: error: invalid conversion from ‘int’ to ‘int*’ 
 int *arr[3] = { 1, 2, 3 };
                         ^
pointers.cpp:2:25: error: invalid conversion from ‘int’ to ‘int*’ 
pointers.cpp:2:25: error: invalid conversion from ‘int’ to ‘int*’ 

但是,如果您强制转换,C ++也可以:

int *arr[3] = { (int*)1, (int*)2, (int*)3 };

即使没有警告也可以编译。