指针只是一个整数吗?

5
如果我知道一个数据对象的地址,我能将该地址存储为整数,并将整数作为指针来操作吗?
例如:
void main(){
    long a = 101010;
    long *p = &a;
    long b = p;
    printf("%lld\n", *(long*)b);
}

它总是安全的吗?

评论:long b = p; 会产生一个警告:

Initialization makes integer from pointer without a cast

然而,该程序打印出101010

1
语言标准中没有规定指针总是可转换为整数。这只是一个巧合,就像 int 现在某种原因变成了 long 一样。 - Alexander V
这段代码应该会产生一个警告,因为它在没有进行强制类型转换的情况下将指针用作整数。 - user3629249
如果您将此代码放入文件并编译它(启用警告),编译器会将代码标记为不正确。那么就没有必要问这个问题了。 - user3629249
没有什么东西是总是安全的;当然,指针不仅仅是一个整数,但它总是可以表示为一个整数(它可能是一个int或一个long,甚至是一个30位的值,但你可以声明它是一个整数)。 - Elliott Frisch
在非线性寻址架构(例如x86实模式)中,指针甚至可能不是单个数字。例如(再次提到)在x86实模式中,所谓的“FAR”指针是由段地址和段内偏移量组成的。 - Euro Micelli
我不明白。如果指针不是整数(长整型、短整型、二进制或其他),它还能是什么?谢谢。 - posixKing
5个回答

7

标准不能保证这样的类型转换总是有效的。

使用 intptr_t(或它的无符号版本 uintptr_t)将指针存储在整数类型中。它保证可以将 void * 指针转换为这些类型,并进行转换后得到相同的值。

请注意,这些类型是可选的。


它们通常与ptrdiff_t(带符号)和size_t(无符号)相同,是吗? - technosaurus
1
@technosaurus 不完全是这样。同时请注意,ptrdiff_tsize_t并非可选项。 - Yu Hao

2

sizeof(long)通常由编译器定义(受底层硬件架构的影响)。

sizeof(long *)取决于您平台上的虚拟内存地址空间大小。

例如,在64位操作系统和基于x64的处理器上使用Visual Studio编译器:

  • sizeof(long) == 4
  • sizeof(long*) == 8

因此:

  • 对于long b = p,只复制了p的最低有效字节到b
  • 使用*(long*)b访问无效的内存地址是有可能的

在这个例子中,如果p的四个最高有效字节为0,则“不会造成伤害”。但由于不能保证这种情况,当sizeof(long)!=sizeof(long*)时,此代码通常是不安全的。

此外,即使sizeof(long)==sizeof(long*),您仍应避免使用这种类型的转换(指针到整数),以便使代码可移植到其他平台。


更新

请注意,printf("%lld\n", *(long*)b)也是不安全的。

您应该基本上使用"%ld"来表示long值,使用"%lld"来表示long long值。

如果sizeof(long) < sizeof(long long),则可能会导致运行���内存访问冲突。


0

为了保险起见,我们应该考虑它不安全。

在n位系统中指针的大小为n位。例如,在任何64位结构/编译器上,指针大小应为8字节。这是有保证的。

然而,数据类型没有这样的保证。它很大程度上取决于编译器。在你的情况下,两者恰好具有相同的大小,这就是为什么它能工作的原因。


编辑:

关于警告

Initialization makes integer from pointer without a cast

你的编译器在发出警告方面是非常正确的。请检查数据类型。一个 int * 变量不等于一个 int 变量。在你的情况下,它之所以能够工作,只是因为在你特定的情况/实现中长度相同。


0

即使p值和b值相同,只有p可以访问a,即可以指向ab无法指向a。因为p被声明为指针,而b被声明为变量。

您无法通过b访问a。那么您的问题如何适用?在b中,a的地址被视为仅是value而不是address,因为b是变量而不是指针。

即使它打印101010,这个程序也不是通用的。


-1
指针是一个变量,其值是另一个变量的地址。与任何变量或常量一样,在使用指针之前,必须先声明它。指针变量声明的一般形式为:
type *var-name;

所有指针的实际数据类型,无论是整数、浮点数、字符或其他类型,都是相同的,即表示内存地址的长十六进制数。不同数据类型的指针之间唯一的区别在于指针所指向的变量或常量的数据类型。

指针通常具有固定的大小,例如在32位可执行文件上它们通常是32位。有一些例外情况,比如在旧的16位Windows系统中,你必须区分32位指针和16位指针... 在现代桌面操作系统中,通常可以安全地假设它们在给定的可执行文件中是统一的。


尽管将类型转换为保证具有相同大小的类型非常容易... - Michael Gazonda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接