繁体   English   中英

关于数组被“归零”的困惑

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM