go - 为什么 unsafe.Sizeof 返回一个 uintptr?
问题描述
根据文档(https://golang.org/pkg/unsafe/#Sizeof)unsafe.Sizeof
返回给定表达式的大小(以字节为单位)。理想情况下,任何给定表达式的大小都可以用 auint32
或表示uint64
。那为什么 Golang 会返回 auintptr
呢?这不是很混乱吗?Auintptr
应该保存一个指向某个数据值的指针,但在这种情况下,它实际上不是一个指针,它只是一个数字,对吧?
解决方案
评论中有很多很好的答案,归结为“因为它足够大,但又不太大”。不过,我认为从历史的角度来看这可能会有所帮助,特别注意这一切是如何在 C 编程语言中发生的。
在非常古老的(准标准)C 中,如果你能追溯到足够远的时间,甚至没有明确的unsigned
整数类型。PDP-11 具有:
char
, 8 位,有符号;int
, 16 位,有符号;和- 指针,16 位,无符号。
那是:
int i;
int *u;
是你如何制作两个整数,i
有符号和u
无符号。设置i
为 32767 (0x7fff) 然后增加它给你 -32768 (0x8000),它逐渐增加到 -1 (0xffff) 然后为零。设置u
为 32767,然后增加它给你 32768,它逐渐增加到 65535,然后翻转到零。
整数和指针之间缺乏区别意味着设备驱动程序可以读取:
struct {
int csr;
int blk;
int bar;
int bcr;
};
0177440->bcr = count;
0177440->blk = block;
0177440->bar = addr;
0177440->csr = READ | GO;
这可能就是告诉设备读取一些字节或块的方式。
(这也是为什么结构成员名称,如st_ino
in struct stat
,都以这样的前缀表示:st_ino
仅表示“一些整数偏移量”,您可以将st_ino
成员与任何指针一起使用,甚至可以与普通变量一起使用。前缀意味着您可以在#include
没有多个标题的情况下使用它们的结构成员名称发生冲突。)
当 C 语言在 32 位和其他机器上工作时,所有这些都变得站不住脚了。C 增加了一个unsigned
整数类型,而不是将指针作为无符号整数来服务,Steve Johnson 的 PCC 编译器变成unsigned
了一个修饰符,可以应用于char
和short
以及int
. 进行了大量的实验。最终,在 1989 年,C 首次使用我们现在拥有的大部分语法和语义进行了标准化(尽管新标准添加了新类型和许多函数,等等)。
一些早期的 C 语言先驱参与了 Go 的创建,尤其受到Ken Thompson的影响。维基百科页面上有一个合适的引用:
当我们三个人 [Thompson、Rob Pike 和 Robert Griesemer] 开始工作时,那是纯粹的研究。我们三个人聚在一起,决定我们讨厌 C++。[笑声] ... [回到 Go,] 我们一开始的想法是,我们三个人都必须被告知该语言的每个功能,因此不会出于任何原因将无关的垃圾放入该语言中。
正如我们在早期的 C 语言中所看到的,作为整数的指针是一种合适的无符号类型,它不仅可以保存任何指针,而且如果被视为无符号,还可以保存任何对象大小。当然,作为整数的指针不能直接用作指针,并且对于 GC 系统和并发性,我们需要语言本身具有指针。但是我们还需要能够为该语言编写运行时支持, 1为此我们需要整数化指针,这也涵盖了我们对对象大小的所有需求。因此,编译器内置的一种类型涵盖了所有需求。那是尽可能简单,但并不简单。
1我说“我们”,就好像我和它有什么关系一样。很明显,一旦您实现了一些运行时系统。
推荐阅读
- google-api - 使用服务帐户使用 Google Drive API 创建文件不会在授权用户帐户的 GD 上呈现文件
- javascript - Material UI 自动完成,多个默认值
- lua - 尝试在 Lua/Love2D 中绘制平台时出错
- node.js - 执行 npm start 时出现 Azure 函数节点错误
- javascript - 从javascript中的异步函数获取返回值
- django - 除非打开 chrome 开发人员工具,否则 React/Redux 应用程序无法工作?
- javascript - InfiniteScroll - 如何重置所有网格?
- css - 是否可以在不同的屏幕中查看页面?
- quill - 如何使 Quill delta 输出变平?
- c++ - 分支定界根节点是否适合使用继承?