当前位置: 首页 > 知识库问答 >
问题:

C语言中所有指针的大小都一样吗

杨飞飙
2023-03-14

我知道了

所有指针具有相同的大小是很常见的,但是指针类型具有不同的大小在技术上是可能的。

但后来我发现了这样一句话:

虽然指针都是相同的大小,因为它们只存储一个内存地址,但我们必须知道它们指向什么样的东西。

现在,我不确定哪一个是正确的。第二个引用的陈述看起来像是来自佛罗里达州立大学计算机科学的注释。

以下是我的想法:

  1. 假设我们有:
int i = 0;
void* ptr = &i;

现在,假设C标准允许指针有不同的大小。进一步假设在一些任意的机器/编译器上(因为它是标准允许的),一个空*的大小为2个字节,而一个int*的大小为4个字节。现在,我认为这里有一个问题,即上面片段中显示的语句的右侧有一个int*,它的大小为4个字节,而在左侧,我们有一个空*,它的大小为2个字节。因此,当隐式转换发生在从int*ull*之间时,会有一些信息丢失。

这是所有指针大小相同的第一个原因(IMO)。

使用上面的两点,我认为第二句话是正确的。

我的第一个问题是C标准对此有何规定?

我的第二个问题是,如果C标准允许指针大小不同,那么这有什么原因吗?我的意思是,允许指针大小不同对我来说似乎有点不自然(考虑到我上面解释的两点)。所以,我很确定标准委员会一定已经考虑过(指针可以有不同的大小),并且已经有理由允许指针有不同的大小。请注意,只有当标准允许指针具有不同的大小时,我才会问这个问题(第二个问题)。

共有3个答案

潘嘉佑
2023-03-14

一些规则:

>

  • 普通旧数据指针的大小可以不同,例如双*可以(并且经常)大于int*。(想想具有板外浮点单元的架构。)

    必须足够大以容纳任何对象指针类型。

    任何非普通旧数据指针的大小都与其他指针相同。换句话说,sizeof(myclass*)==sizeof(yourclass*)

    sizeof(const T*)与任何Tsizeof(T*)相同;普通的旧数据或其他

    成员函数指针不是指针,指向非成员函数的指针,包括<代码>静态 成员函数,是指针。

  • 逑何平
    2023-03-14

    成员函数指针可以不同:

    void* ptr;
    
    size_t (std::string::*mptr)();
    
    std::cout << sizeof(ptr) << '\n';
    std::cout << sizeof(mptr) << std::endl;
    

    这个打印出来的

    8
    16
    

    在我的系统上。背景是成员函数指针需要保存额外的信息,例如关于虚拟性等。

    历史上,有一些系统上存在着大小不同的“近”和“远”指针(16位和32位)——但据我所知,它们现在不再发挥任何作用。

    朱昊乾
    2023-03-14

    虽然很容易得出结论,所有指针都是相同大小的,因为“指针只是地址,地址只是相同大小的数字”,但标准并不能保证这一点,因此不能依赖它。

    C标准明确保证:

    • 空*char*大小相同([basic.compound]/5)
    • T const*T易失性*T const易失性*T*具有相同的大小。这是因为相同类型的cv限定版本是布局兼容的,并且指向布局兼容类型的指针具有相同的值表示形式([basic.compound]/3)。
    • 同样,具有相同基础类型的任何两个枚举类型都是布局兼容的([dcl.enum]/9),因此指向此类枚举类型的指针具有相同的大小。

    标准并不能保证这一点,但实际上,指向所有类类型的指针大小相同,这一点基本上总是正确的。原因如下:指向不完整类类型的指针是完整类型,这意味着即使T是不完整的类类型,您也有权询问编译器sizeof(T*),如果定义了T之后在翻译单元中再次询问编译器sizeof(T*),结果必须相同。此外,在声明了T的每个其他翻译单元中,结果也必须相同,即使它从未在另一个翻译单元中完成。因此,编译器必须能够确定T*的大小,而不知道T的内部内容。从技术上讲,编译器仍然可以玩一些把戏,比如说,如果类名以特定前缀开头,那么编译器将假定您希望该类的实例接受垃圾收集,并使指向它的指针比其他指针更长。实际上,编译器似乎没有使用这种自由度,您可以假设指向不同类类型的指针大小相同。如果你依赖这个假设,你可以在你的程序中放置一个静态断言,并说它不支持违反该假设的病理平台。

    此外,在实践中,通常情况下

    • 任何两种函数指针类型的大小都相同,

    这样做的原因是您总是可以reinterpret_cast从一个函数指针类型到另一个函数指针类型,然后返回到原始类型,而不会丢失信息,对于上面(expr.reinterpret.cast)列出的其他两个类别,依此类推。虽然编译器允许通过给它们不同数量的填充来使它们具有不同的大小,但没有实际的理由这样做。

    (然而,MSVC有一种模式,指向成员的指针不一定具有相同的大小。这不是因为填充量不同,而是违反了标准。因此,如果你在代码中依赖于此,你可能应该在

    如果您有一个分段的体系结构,带有近指针和远指针,那么您不应该期望它们具有相同的大小。这是上述规则的一个例外,即某些指针类型对通常具有相同的大小。

     类似资料:
    • 我知道了 所有指针具有相同的大小是很常见的,但是指针类型具有不同的大小在技术上是可能的。 但是后来我看到这个上面写着: 虽然指针的大小都一样,因为它们只存储一个内存地址,但我们必须知道它们指向的是什么类型的东西。 现在,我不确定哪一个是正确的。第二个引用的陈述看起来像是来自佛罗里达州立大学计算机科学的注释。 以下是我的想法: 说我们有: 现在,假设C标准允许指针有不同的大小。进一步假设在某些任意机

    • C 语言的指针常常被人们认为是 C 语言中的灵魂所在,可以完成很多高难度的操作。但是更多的人感觉 C 语言的指针的存在如同噩梦一般,因为稍不注意,就会引起灾难性的后果。 不管你是不是喜欢 C 语言中的指针,我们都要学习这种看起来很神奇的东西。因为指针这个概念不是 C 语言首创的,而是苏联的计算机科学家首创的。 1. 什么是指针? 指针是什么?这是来自灵魂的拷问。其实指针也是一种变量。我们之前也说过

    • 多级指针概述 我们将指针变量理解为一个存储地址的变量。如果这个地址里面存储的依然是地址,那么我们就可以定义一个二维指针。通过一个二维指针,我们通过两次寻址操作就可以找到这个值。 比如我们定义一个int **p;这是一个二维指针,当编译器看到p的时候,它知道这是一个指针变量,指向一个地址;当它看到第二个的时候,它知道指向的地址里面依然还是地址。如下图所示: 如果我们将p[0]和p[1]分别指向两个字

    • 我们已经在内存中看到了int类型的存储方式,如果我们存储的是0x12,就会在内存中得到二进制的编码0001 0010。如果我们存储一个float类型的1.2,又在内存中又有怎样的存储方式呐?下面我们使用两种方法来读取存储在内存中的float变量。 用int类型的指针来读取同样大小的四个字节 测试代码如下 我们可以看到由于不同的指针类型赋值,依然有一个警告。 运行结果如下 这就是浮点数1.2在内存中

    • 下面为了让大家更好的理解上面两个概念,我们来举几个例子来查看一下。 解释第一个概念:大小一样的盒子存储指针 代码如下 我们声明了两个类型的变量,它们的类型是不同的。我们通过sizeof来查看这两个指针变量的大小。 #include <stdio.h> int main(){ int *p1; char *p2; printf("the p1 is %u, th

    • 今天我们进入到嵌入式C语言高级部分的第三个内容-C内存空间的使用。 学习目的 在本章内容中,我们将给大家展示一下C语言对于内存空间指向和内存空间使用上的一些技巧。在我们上一个阶段中,我们只是明白了C语言给我们带来的关键字和运算符。但是C语言的核心-操作内存资源的方式方法,这些我们没有介绍。在本个学习阶段,我们将重点围绕C语言访问内存空间的方式,以及访问空间需要使用的一些技巧来展开。 指针介绍 之前