【问题标题】:typecast a char * to int *将 char * 类型转换为 int *
【发布时间】:2017-07-28 02:36:31
【问题描述】:

我有一个给定的字符串

char *names = "ABC";

现在,作为理解指针和它的一部分,我想将字符串转换为 ascii 代码,但使用 pointer

这是我到目前为止所做的。

 char *name = "ABC";
 int *array;
 array = (int *) name;
 printf("the array value is %d ",*array);

但不幸的是,我无法理解为什么它将 4407873 打印为值。

注意:我也知道可以使用 atoi 函数完成,但如果我能理解如何执行上述方法,那将非常有帮助。

【问题讨论】:

  • 十六进制字符串的四个字节(包括终止符)是41 42 43 00。你的机器是 little-endian,所以当将这 4 个字节读取为int 时,它们会反过来使用,十六进制00434241,十进制是4407873。但这无论如何都是不好的行为。
  • 不清楚你在问什么。 “ABC”的ascii代码是什么意思?使用 atoi 可以做什么?
  • 您的意图非常清楚,但看起来,您对指针、强制转换和其他 C 语言基础知识存在根本性的误解。请帮自己一个忙,读一本 C 书。
  • 您希望打印出什么数字?我们可能会告诉您如何到达那里。
  • 尽管有名字,char 不是字符类型——它是一个整数类型。在许多环境中,'A'==65 是正确的。

标签: c pointers strict-aliasing typecast-operator


【解决方案1】:

在您的代码中,使用 array 作为指向整数的指针

printf("the array value is %d ",*array);

array 被赋予了类似的值

array = (int *) name;

name 被定义为

char *name = "ABC";

违反strict aliasing rulecharint 不是兼容类型,因此程序无效。

引自C11,第 6.3.2.3 章,

指向对象类型的指针可以转换为指向不同对象类型的指针。如果 结果指针未正确对齐引用的类型,行为是 不明确的。否则,当再次转换回来时,结果将等于 原始指针。 [...]

因此,如果使用非别名类型来访问内存,它会调用undefined behavior

【讨论】:

  • @SouravGhosh。我想我知道你想说什么,即 int 是 4 个字节(取决于机器)而 char 是 1 个字节,对吧?但是你能解释一下吗?作为参考。
  • @Ratatouille 是的,基本上就是这样,但还有更多。我在答案中的严格别名中添加了详细且描述良好的资源,希望对您有所帮助。 :)
  • @Ratatouille 每个 char 是 1 字节,您的 字符串文字 "ABC" 是 4 字节(例如 { 'A', 'B', 'C', '\0' } 包括 nul-终止字符)。硬件期望int 存储在内存中的方式将取决于硬件的字节序
  • @DavidC.Rankin:有效的类型规则不仅仅是对齐和对齐。假设指针不能别名,编译器可以安全地应用优化。
  • @2501:您可以将指针投射到另一个然后返回。这并不意味着您可以取消引用转换的指针值!在 C 中,对象的类型由它的 defined 类型(或用于没有类型的对象的最后一次写入它的类型定义,而不是由用于访问它的指针的类型定义。任何东西else 本质上是不安全的(不包括 char 的旧版本)。
【解决方案2】:

理解指针的一部分是理解对它们做什么。您应该对指针做的主要事情之一是尝试使用指向不兼容类型的指针来访问一种类型的对象。

例如,使用指向char 的指针从char 数组中读取元素很好,使用指向const char 的指针也很好,但是指向int 的指针是一个很大的禁忌。

这样做的结果是未定义的行为,这意味着它可能导致您的程序执行任何事情。 (不要被看似一致的行为所迷惑——未定义的行为也允许这样做,然后在您确信可以使用未定义的行为和不会相信这是错误的原因)

【讨论】:

    【解决方案3】:

    在 C 语言中,像int 这样的大多数类型通常会存储为两个或多个连续字节的序列。写入int* 会将写入的值转换为字节序列并连续存储它们。读取int* 会读取一个字节序列,然后将它们转换为整数。

    然而,并不是每个连续整数序列都可以被解读为另一种类型。实现可能会施加三种限制:

    1. 在某些实现中,某些字节序列可能不代表某些类型的值。例如,可能要求浮点值的第一个字节在 0-126 或 128-254 范围内;尝试加载第一个字节为 127 或 255 的值可能会以任意方式捕获,具体取决于实现。

    2. 在许多实现中,内存在物理上被划分为 2、4 或 8 个字节(有时称为“字”)的组,并且可能需要某些类型和大小的对象在相应的边界上开始 -大小的组(例如,如果“int”是 4 个字节,则系统可能只能加载适合单个 4 字节字的“int”数量。尝试加载跨越字边界的 int* 可能会失败任意后果,具体取决于实施。

    3. 虽然某些应用程序领域可能会从能够使用不同类型读取和写入存储中受益匪浅,但其他领域的许多应用程序却没有任何好处。如果编译器可以假设一种类型的对象不会受到另一种类型的指针的影响,编译器可能会生成更有效的代码,并且标准的作者没有试图要求实现适用于任何特定领域。因此,标准不要求实现对将存储作为一种类型写入和作为另一种类型读取的效果做出任何承诺,即使在满足对齐要求并且位模式有意义且

      打算在此类翻译有用的领域中使用的实现应指定他们承诺以有意义的方式处理此类操作的情况,而不这样做的实现可能不适合用于以下目的需要此类功能,但仅用于此类功能不会提供任何好处的应用程序的实现不需要提供超出标准中给出的最低限度的任何此类功能。

    请注意,第三点引起了很多激烈的争论,因为编译器编写者没有认识到,当标准的作者没有尝试要求所有实现适合任何特定目的或应用领域时,因此没有尝试强制支持使编译器适用于任何特定目的或领域所需的所有行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 2017-01-22
      • 1970-01-01
      • 2017-04-17
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 2012-08-07
      相关资源
      最近更新 更多