[英]Using calloc in C to initialize int array, but not receiving zeroed out buffer
[英]Confusion about array being “zeroed out”
#include<stdio.h>
#include<stdlib.h>
static char mem[4];
int main()
{
int* A = (int*)(mem);
mem[0] = 0;
mem[1] = 1;
mem[2] = 2;
mem[3] = 3;
int i;
A[0] = 5;
for (i = 0; i<4; i++)
{
printf("%d\t", mem[i]);
}
printf("\n");
return 0;
}
我的问题是,为什么打印5 0 0 0而不是5 1 2 3? 为什么数组“被清除了”?
在你的情况下
A[0] = 5;
将5
写为整数 ,其大小大于char
(2、4、8,取决于)。
您的系统似乎是little endian,因此在第一个char
位置写入5,然后在零位置写入。
请注意,如果sizeof(int)
为8(在某些系统上可能会发生),则您的代码将不安全,并会触发未定义的行为,因为它会覆盖mem
数组后的内存(更不用说可能会导致操作速度变慢甚至崩溃的未对齐问题)在某些处理器上)
这就是为什么我们必须遵守严格的别名规则,以避免“说谎于编译器”的原因,例如,创建一个union
以便编译器可以调整对齐和检查大小。
另一个与Q&A相关的问题是: 如果在地址中未将字对齐时将char *地址转换为int *,会发生什么情况?
因为在您的系统中sizeof int
至少是sizeof(char)
4
倍,所以要花4
个字节来覆盖您编写的所有内容,因为A
是一个指向int
的指针。(但是它可能花费更大的时间)(这种情况是通常是)如果不是,这是未定义的行为。
还要注意,我们如何编写它取决于字节序。 在您的情况下,它是小端的。 因此,根据字节顺序,它也可能有所不同。 不管这仅具有实验目的。
还给您一个想法,当sizeof(int)
大于4
时为什么它是UB-然后您将通过A[0]
访问该数组存储器中的一些内存,并尝试对其进行修改并对其进行更改-导致未定义的行为。
您尝试使用int
针对char *
类型进行别名时,您的代码表现出未定义的行为。 这违反了严格的别名规则,因此您的代码简直是错误的。
char *
类型可以别名其他指针类型,但不能相反。 因此,请确保不违反语言的约束。
int* A = (int*)(mem);
- >风险每未定义的行为 “如果所得的指针未正确用于该被引用类型对齐,该行为是未定义”。 C11dr§6.3.2.37
因此,其余代码尚无定论。
使用union
来解决对齐和抗锯齿问题。
#include <stdio.h>
int main(void) {
union {
int i;
unsigned char mem[sizeof(int)];
} u;
for (unsigned i = 0; i < sizeof(int); i++) {
u.mem[i] = i;
printf("%hhu\t", u.mem[i]);
}
printf("\n");
u.i = 5;
for (unsigned i = 0; i < sizeof(int); i++) {
printf("%hhu\t", u.mem[i]);
}
printf("\n");
return 0;
}
输出(可能因您的机器而异)
0 1 2 3
5 0 0 0
原因:既然已从代码中删除了未定义的行为 UB, Jean-FrançoisFabre好的答案就解释了这些区别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.