【问题标题】:While trying to understand a pointer, I have the following concern在尝试理解指针时,我有以下担忧
【发布时间】:2016-06-26 16:52:59
【问题描述】:

在最后两个语句中,realPointerfakePointer 之间的任何实际区别。它们会提供相同的功能吗?

  int num = 0;

  int *realPointer = #
  int fakePointer = #

【问题讨论】:

  • 当询问“这两位 C 代码是否提供相同的功能”时,请发布实际编译的代码。上面的一个变量做了一些事情,另一个是编译时错误:很明显,编译时错误与编译时的功能不同。
  • @Yakk 使用gcc(例如),这只是一个警告,而不是错误:warning: initialization makes integer from pointer without a cast

标签: c pointers type-conversion


【解决方案1】:
int num = 0;
int *realPointer = #
int fakePointer = #

在最后两个语句中,realPointer 和 fakePointer 之间的任何真正区别。

您的fakePointer 不是指针。它是一个整数,其值为变量 num 的地址。使用默认选项编译它时,您可能会逃脱。但正如 Lundin 所指出的,这确实是一个无效的代码。使用 gccCFLAGS="-g -Wall -std=c99 -O3 -pedantic-errors" 标志,你会得到这个错误:

 error: initialization makes integer from pointer without a cast

虽然您的 realPointer 确实指向变量 num,但您可以取消引用它。你不能用你的fakePointer 做这样的事情——事实上,分配给fakePointer 本身是无效的。

【讨论】:

    【解决方案2】:

    声明为指针的变量在语义上不同于未声明为指针的变量。编译器(和语言)将允许你用指针做你不能用非指针做的事情。当然相反。

    最大的不同是您可以取消引用指针,但不能对非指针执行此操作。

    例如,在你的代码中使用变量,那么我们可以通过*realPointer = 5 使num 赋值为5,但是*fakePointer = 5 是不允许的,因为@987654325 是没有意义的@ 实际上不是指针。

    【讨论】:

      【解决方案3】:
      int fakePointer = #
      

      这不是有效的C,它违反了简单赋值的规则,不会编译。

      但是,如果您完成了int fakePointer = (int)#,那么唯一的区别就是不能保证您可以可靠地使用 fakePointer,从指针到整数的转换是实现定义的,并且还可能导致未定义的行为 (6.3.2.3 ):

      任何指针类型都可以转换为整数类型。除了作为 之前指定的,结果是实现定义的。如果 结果不能用整数类型表示,行为是 不明确的。结果不必在任何值的范围内 整数类型。

      为了安全且可移植地在指针和整数之间进行转换,您不应使用 int,而应使用 stdint.h 中的 uintptr_t 类型。

      【讨论】:

      • 为了 OP 的利益,有人可能会补充说,指针大小通常是 64 位,嗯,64 位架构(具有 64 位操作系统的现代 PC 处理器),而 int 甚至大小在 64 位架构上通常是 32 位(x86_64 Cygwin/Windows 7/core i7 上的 gcc 4.9.3,以及针对 x64 的 Visual Studio 2013,同一台 PC)。在这样的系统上,指针 -> int -> 指针转换会导致缺少高 32 位的无效地址。
      • @PeterA.Schneider 更重要的是,int 是有符号类型,但不存在负地址。因此,如果int 是 32 位,而您的指针类型是 32 位,它也不起作用,在转换设置了 msb 的指针时,您会调用未定义的行为。
      • @Lundin:我认为 C 标准并不关心是否存在负地址。从某种意义上说,当前的 x86-64 系统同时使用正虚拟地址和负虚拟地址,通常在用户/内核边界处拆分。
      • @IanAbbott:这不是问题。问题是 C 不能保证所有位模式都是有效的整数,所以你可以产生一个陷阱表示。
      • @Kevin:问题不在于地址可能是负数,也可能不是。问题在于将指针值转换为不能表示该值的整数类型会导致未定义的行为。 (但我们只是在这里争论琐碎的语义!)
      【解决方案4】:

      如果你选择这两个变量持有的字面值(即实际值),它们是相同的(即变量 num 的地址),但只有值相同。 但正如其他人所说,它们在语义上是两个不同的变量,不能互换使用。

      最后一个问题:

      它们会提供相同的功能吗?

      回答:不,他们没有。

      推理它们不是同一类型。

      你的第一个问题:

      realPointer 和 fakePointer 之间的任何真正区别。

      有很多区别,最基本的区别是:
      1. realPointer 保存 num 的地址并且是一个指针,因此如果您更改 num 的值(通过使用 num 变量或 *realPointer 进行更改),它会在两个位置反映出来,但 fakePointer 不是这种情况李>
      2. 您可以将 realPointer 传递给函数,并且在函数调用中所做的任何更改都将反映回被调用函数。

      【讨论】:

        【解决方案5】:

        除了这个

         int fakePointer = #
        

        可能导致以下一种或多种情况

        • 通过破坏 C 语言的“规则”(这反过来可能导致“任何事情发生”)导致的未定义行为
        • 转换期间丢失有效数字
        • 完全编译失败

        适用以下差异:

        • *-/dereferencing-operator 不能应用于int 类型为fakePointer
        • 执行fakePointer++ 很可能会导致与执行realPointer++ 不同的结果。这适用于添加和减去任何值的所有其他方式(但0)。阅读 "pointer arithmetic" 与“算术”了解详细信息。
        • 不能将[]-/indexing-operator 应用于int 类型为fakePointer

        【讨论】:

          猜你喜欢
          • 2011-03-01
          • 2012-04-30
          • 2014-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-25
          • 1970-01-01
          相关资源
          最近更新 更多