golang 里面为什么要设计 int 这样一个数据类型?

2021-01-14 15:23:28 +08:00
 jiangwei2222

在 golang 里面,有 int64,int32,int 这 3 种数据类型。

int64: 占 64 位的整数数据类型

int32: 占 32 位的整数数据类型

int: 在 64 位处理器上占 64 位,在 32 位处理器上面占 32 位

于是我就纳闷了,int 这个数据类型不是埋坑吗?不同的处理器上面可能导致不同的运行结果,那设计这个数据类型的意义是啥呢?为啥不只保留 int64 和 int32,由程序员指定长度,保证运行结果的一致性

我 google 查了很久,没找到相关的资料,还望了解的老哥赐教

5166 次点击
所在节点    Go 编程语言
19 条回复
xuanbg
2021-01-14 15:27:25 +08:00
因为程序员往往不能预知他写的代码会在什么环境下运行……
wudicgi
2021-01-14 15:30:01 +08:00
老哥没见过 C 语言里的 int, int32_t, int64_t ?
jiangwei2222
2021-01-14 15:31:32 +08:00
@xuanbg #1 就因为不能预知,所有指定使用 int64 或者 int32 不更加保险吗
no1xsyzy
2021-01-14 15:33:22 +08:00
有一个可能性是为了效率,在 64 位上为了 int32 需要 runtime 手动限制只使用低 32 位,可能需要手动调整溢出 flag ?
32 位上 int64 是必然需要模拟的……
ruyu
2021-01-14 15:35:32 +08:00
在不 care 最大值的时候使用 int, 让所有的 CPU 都开心.
no1xsyzy
2021-01-14 15:36:01 +08:00
如果说你肯定该数远远达不到 int32 和 int64 (比如一个 flag,只能取 012,其他均视为未定义行为),那么这个 overhead 就比较明显了。
而如果你有一百万个这样的数……
zoharSoul
2021-01-14 15:36:56 +08:00
我也挺纳闷的
icexin
2021-01-14 15:38:43 +08:00
int 跟机器字长一致,这样可以获取最大的执行效率。在不关心数值范围的场景下 int 足够了,比如数组下标。相反如果你在 32 位机器上使用 int64,本来一条指令的事情要变成多条指令。
int32 和 int64 这些一般用于编解码、底层硬件相关,或者是数值范围敏感的场景。
xuanbg
2021-01-14 15:41:33 +08:00
@jiangwei2222 如果你指定 x64,在 x86 平台上就跑不起来啦。指定 x86,x64 平台倒是能跑,但性能就浪费了。
eason1874
2021-01-14 15:49:26 +08:00
我的理解相反,int 是平台原生,int32 int64 才是有意设计的
LANB0
2021-01-14 16:06:00 +08:00
在 golang 里面,有 int64,int32,int 这 3 种数据类型。
int64: 占 64 位的整数数据类型

int32: 占 32 位的整数数据类型

int: 在 64 位处理器上占 64 位,在 32 位处理器上面占 32 位

在 c/c++ 里面,有 long long int,int,long int 这 3 种数据类型。
long long int: 占 64 位的整数数据类型

int: 占 32 位的整数数据类型(32 位及 64 位平台,8 位和 16 位不考虑了)

long int: 在 64 位处理器上占 64 位,在 32 位处理器上面占 32 位

实际上,在不需要做存储和通讯协议数据对齐的场景下,long int 是在跨平台情况下效率最高的。
跨平台存储和通讯协议数据对齐场景下,4 字节就固定 int32,8 字节就固定 int64
teawithlife
2021-01-14 16:14:37 +08:00
看到 C99/C++11 的这些,你会更纳闷的
en.cppreference.com/w/c/types/integer
其实原因很简单,就是为了执行效率,一些情况下,我们并不关心 int 到底是 32 位还是 64 位的,反正都够用,这时候就没必要强制指定位数,而是让编译器自己去自行选择效率最高的位数
secondwtq
2021-01-14 20:55:38 +08:00
仅就 x86 而言,int64 还真不一定比 int32 快
“快不快”不仅仅是指令支持的问题,数据宽了一倍,占用的缓存空间、内存带宽都加了一倍。如果真有一百万个这样的数,可能还真是 32 位好一点,特别再考虑到 SIMD 的情况下

如果这货的行为真的像楼主说的一样“在 64 位处理器上占 64 位,在 32 位处理器上面占 32 位”的话,那么看 C/C++ 是正解,不过鉴于大道至简的 Go 目标之一就是干死 C++,估计没人会去看的。

C 里面有一个类型叫 size_t,相当于 Go 的 uint,还有个 ptrdiff_t,相当于 Go 里的 int (假设楼主说的行为是对的)
size_t 顾名思义,可以装下任何对象的“大小”,比如在 32 位环境下,地址空间中不可能存在多于 2^32 个唯一的对象,一个对象的大小也不可能超过 2^32 字节,所以 size_t 做成 uint32_t 就可以。需要存大小、数量时就用这货。
ptrdiff_t 顾名思义,可以装下任意两个指针相减的结果,需要存偏移时就用这货。(不过 C 标准里面貌似没有保证,毕竟真正存差值需要 wordsize+1 位 ...)
毕竟如果是 32 位环境,用 64 位数存数组有多少个元素实在太过奢侈了,这时候根据大道至简的原则,就可以加一个类型叫 int 。

这只是一个猜想,因为 Go 的所谓 spec 实在太大道至简了:
> uint either 32 or 64 bits
> int same size as uint
反正在这两句话我是没找着“在 64 位处理器上占 64 位,在 32 位处理器上面占 32 位”的保证。因为他把这玩意写在后面 builtin functions 部分了:“The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int.”,然后就有了这个 https://yourbasic.org/golang/int-vs-int64/ 。也就是说这个类型和它的角色并不直接关联,可能本来设计者的想法就是从 C 里面随便捣鼓来的 ...
secondwtq
2021-01-14 21:10:42 +08:00
噢对了补充下,我知道做优化的时候有至少一种情况会把 32 位数故意 widen 成 64 位,就是频繁转换的时候。
具体来说,是一个循环的 induction variable ( https://en.wikipedia.org/wiki/Induction_variable )被定义为 32 位,但是使用时总是先 cast 成 64 位再使用,这种情况用 64 位数代替原来的 induction variable 可以省去转换的开销,并且就一两个变量一般都放寄存器里面,做起来才值得。
(嘛不过我只是观察到这么一种行为,并没有找到对应的参考,也没有仔细看相关的代码 ...)
douyacun
2021-01-14 22:43:26 +08:00
自 2008 年 1 月起,Ken Thompson 就开始研发一款以 C 语言为目标结果的编译器来拓展 Go 语言的设计思想。

c 有 go 就有了,因为顺手~

grpc 就果断抛弃了 int
jiangwei2222
2021-01-15 11:02:04 +08:00
@secondwtq 多谢大佬解释
INCerry
2021-01-15 13:45:22 +08:00
那你可以用 C# C#在 64 位或者 32 位系统中 int 都是 Int32
binlearn
2021-01-15 13:58:56 +08:00
如果我没有猜错,这应该是不同平台“字节对齐”的原因。用 int 能保证字节对齐
coolesting
2021-01-15 20:49:27 +08:00
类型细分化,按需分配内存,工作更效率,和 rust 的设计同出一策,所以这两门语言在未来肯定会称霸一方。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/744921

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX