【问题标题】:Can integer be typecast to pointer to integer?可以将整数类型转换为指向整数的指针吗?
【发布时间】:2014-11-11 19:39:04
【问题描述】:

int 转换为int* 是否有效?如果是,那是什么意思?如果没有,问题是什么?

int a=10;
printf("%d", (int *)a);

只是a 而不是&a。 它在 devc++ 中打印 10。 (int *)a 不是指指向地址 10 的指针,而不是指向存储值 10 的某个地址的指针吗?

啊!我仍然很困惑。我还有一种情况我无法弄清楚。

int b=516;
printf("\n %d",((char *)b));

它打印 516。它不应该打印 4 吗? 请解释一下。

【问题讨论】:

  • 你可以。这并不意味着它会有意义。取消引用时,它将跳转到 int 中的位所代表的内存地址。
  • 您正在做两件未定义行为的事情 - 您将 int 转换为 int *,然后使用 %d 打印 int * 值。在您的编译器和机器上,这两个错误的效果是相互抵消并打印 10。
  • 您正在使用“%d”,这意味着“我保证参数是一个 int”。试试“%p”。 (然后你会遇到一个未定义行为的实例,而不是两个。)或者使用cout << reinterpret_cast<int *>(a)
  • @GregHewgill 只有指针和 int 的大小与我假设的相同。
  • @Oncaphillis:是的,在某些编译器/机器组合上,上面的代码不会输出 10。

标签: c++ c pointers casting type-conversion


【解决方案1】:

根据 C 标准(6.3.2.3 指针)

5 整数可以转换为任何指针类型。除了作为 先前指定,结果是实现定义的,可能不是 正确对齐,可能不指向被引用的实体 类型,并且可能是陷阱表示。67)

在你的代码 sn-p

int a=10;
printf("%d", (int *)a);

指针 (int *)a 可能未正确对齐,例如当 sizeof(int *) 等于 4 或 8 时。 还要考虑到这个调用 printf

printf("%d", (int *)a);

有未定义的行为,

来自 C 标准(7.21.6.1 的 fprintf 函数——同样适用于 printf)

9 如果转换规范无效,则行为是 undefined.275) 如果任何参数不是正确的类型 相应的转换规范,行为未定义。

至于这段代码sn-p

int b=516;
printf("\n %d",((char *)b)); 

然后编译器将堆栈值 516 作为地址推送,但在函数 printf 内部,并且由于格式说明符 %d,该函数再次将此值视为整数对象并相应地输出。

【讨论】:

  • (int *)a 是否也违反了strict aliasing 规则,激怒了另一个 UB?我总是很难识别它。
  • @Grzegorz Szpetkowski 没有退格。只是指针没有正确对齐,并且大小可能大于 int 的大小。
  • 感谢弗拉德。您能否也解释一下问题的第二部分?
【解决方案2】:

是的,您可以将整数转换为指针,但语义取决于上下文。整数的位模式将被解释为地址,可能有效也可能无效。

您的示例没有什么意义,虽然 (int*)a 是等于 0xA 的地址,但 %d 格式说明符导致 printf() 在任何情况下都将值解释为整数 - 这就是它打印 10 的原因,但作为一个地址,它的值仍然是 10 - 即使那个地址是无效的。

考虑:

int a = 10 ;
intptr_t p = (int)&a ; // cast a valid pointer to integer 
                       // large enough to hold an address
int ap = (int*)a ;     // a reinterpreted as a pointer

printf( "%d\n", a ) ;           // Print a
printf( "%p\n", &a ) ;          // Print address of a
printf( "%d (0x%X)\n", p, p ) ; // Print p - an integer equal to &a
printf( "%p\n", ap ) ;          // Print ap - a interpreted as a pointer

【讨论】:

  • 您两次发布了相同的答案。我建议删除这个(你对另一个有赞成票)。 (我还没有检查它们是否相同。)- Aaaand,你刚刚删除了有赞成票的那个。
  • 我没有这样做 - 所以或者我的 Chromebook 浏览器是自己完成的!这个版本是最新的和最正确的。我没有足够的精力去追逐赞成票。
  • 如果您错过了对我之前评论的更新,您可能需要取消删除另一个答案并删除这个答案,这样您就不会失去投票。
【解决方案3】:

intint* 的演员表未定义。这意味着任何事情都可能发生。 可能会发生什么,它将指向索引为 10 的内存块,无论这意味着什么。可以实现一些编译器,使intint* 具有不同的大小,这会导致不同的问题。

知道,如果你运气好,(int *)a 指向地址 10,并且你想看看那里有什么,你可以用

取消引用它
printf("%d", *(int *)a);

警告:这可能/可能/可能会导致类似于忘记malloc内存的分段错误。

TL;DR:不要这样做。

【讨论】:

  • printf("%d", &(int *)a); -- 尝试编译它。 (int *)a 不是左值,因此将一元 & 运算符应用于它是非法的。你的意思是printf("%d", *(int*)a);
猜你喜欢
  • 2015-01-06
  • 2015-06-28
  • 2020-04-30
  • 2022-07-10
  • 2014-08-15
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
相关资源
最近更新 更多