返回信息流默认(u)int为4字节,(u)long为8字节的64位系统
应该怎么理解代码符合 64位可移植性要求?
能否直接理解为,无论在32位或者在64位,变量的内存长度不发生变化,还是说在程序中运算结果不发生变化?
比如
//定义全F
#define MAXVAR 0xFFFFFFFFFFFFFFFFUL
//移位运算
int a=SOME_VAR;//一个常量
long b = (long)(a << 8);
等例子。
/*在不能直接使用_int32、_int64指定长度的情况下*/
这是一条镜像帖。来源:北邮人论坛 / cpp / #93743同步于 2016/10/19
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
[讨论]64位可移植性
shan10211865
2016/10/19镜像同步11 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
用C11/C++11的stdint.h,里面定义了int32_t, uint32_t, int64_t, uint64_t。这个头文件是标准的,可以依赖。
int和long的长度取决于ABI。和平台相关,在同一个平台上(一般由操作系统和CPU两者共同决定,比如Linux-x64, Linux-x86, Windows-x64, OSX-x64, Linux-ARMv7)在不同的平台上基本上没有可移植性。
嗯,我知道可以用stdint.h上面直接定义长度的整型,但是不能用
操作系统是自己扩展linux内核的私人平台,用C,所以不能用C++的标准
可移植性只需要考虑(u)long的变化,就是long(32)->long(64),int不变、pointer不变这种情况,不需要考虑迁移到win,OSX等,只需要考虑linux32位->linux64位
【 在 nuanyangyang 的大作中提到: 】
: 用C11/C++11的stdint.h,里面定义了int32_t, uint32_t, int64_t, uint64_t。这个头文件是标准的,可以依赖。
: int和long的长度取决于ABI。和平台相关,在同一个平台上(一般由操作系统和CPU两者共同决定,比如Linux-x64, Linux-x86, Windows-x64, OSX-x64, Linux-ARMv7)在不同的平台上基本上没有可移植性。
那就只能用宏来自己重新发明轮子了。用sizeof来自己定义定长整数类型吧。
【 在 shan10211865 的大作中提到: 】
: 嗯,我知道可以用stdint.h上面直接定义长度的整型,但是不能用
: 操作系统是自己扩展linux内核的私人平台,用C,所以不能用C++的标准
: 可移植性只需要考虑(u)long的变化,就是long(32)->long(64),int不变、pointer不变这种情况,不需要考虑迁移到win,OSX等,只需要考虑linux32位->linux64位
别人已经发明好了
其实我就是想先讨论一下上面的两个例子满不满足移植性要求
宏定义那个在32位下会截断?
/*已验证64位ul宏可以无报错定义,64位的宏数据展开赋值给int只会传递低32位*/
【 在 nuanyangyang 的大作中提到: 】
: 那就只能用宏来自己重新发明轮子了。用sizeof来自己定义定长整数类型吧。
:
如果软件的基本框架和基本逻辑不变,那么软件从一个平台迁移到另一个平台,应该可以叫移植。而对于目前很多软件而言,当初设计时就已经考虑了跨平台。当然严格意义上讲,Windows XP、Windows 7之间的软件移植或适配或兼容也叫跨平台。
我个人觉得移植是一门很深的工程学,分简单移植和复杂移植,只要软件的核心功能和基本逻辑框架不变,把软件从其设计平台移动到其他平台运行就是软件移植。
个人观点,请暖神指点。 @wht
【 在 nuanyangyang 的大作中提到: 】
: 用C11/C++11的stdint.h,里面定义了int32_t, uint32_t, int64_t, uint64_t。这个头文件是标准的,可以依赖。
: int和long的长度取决于ABI。和平台相关,在同一个平台上(一般由操作系统和CPU两者共同决定,比如Linux-x64, Linux-x86, Windows-x64, OSX-x64, Linux-ARMv7)在不同的平台上基本上没有可移植性。
怎么说呢,我觉得根本问题还是各个平台之间的差异性。如果像Java那样,所有平台上int都是32位,long都是64位,或者像Python那样所有的int都是无穷精度,那也就不必考虑移植、兼容、跨平台了。
然后就应该想想为什么各个平台上有差异了。C语言发明的那个年代,各个平台甚至对一些基本的细节都没有达成一致。比如
- “字长”多大,有的是8位(红白机),有的是16(80286)、32(80386、armv6/v7)、64位(x86_64、aarch64),有的是28位(某个ibm的构架)什么的……
- 有没有浮点运算器?有的话,浮点数怎么表示?1980年代,IEEE754还并没有一统天下。
- 整数运算,溢出了会发生什么?会抛出硬件异常(MIPS)?设置某个溢出标志位(x86)?还是安静地忽略高位(arm在没有S标志时)?
- 除以0会发生什么?抛出硬件异常(x86)?设置某个错误标志位?还是安静地返回某个特殊值(比如0)(arm,可以设置)?
- 有没有栈?栈向高地址增长(sparc,可选),还是向低地址增长(x86、arm)?函数调用的时候,参数的求值顺序是什么?从左到右?还是从右到左?还是随便?
- 内存里存储的定长整数是否需要对齐?如果不对齐,访问内存会发生什么?抛出硬件异常(老的arm)?还是仍然可以正常读写(armv6以后、x86)?
- 对齐的n位整数的内存读写,是原子的吗(x86、arm)?没有对齐的读写(如果可以的话)是原子的吗(x86某些情况下可以,但power、arm不行)?
- 函数指针和数据指针的大小一样大吗?
- 空指针用什么表示?用0地址吗?
- 对0地址读写会发生什么?程序崩溃(linux、windows什么的)?还是发生什么奇妙的事(dos)?
如果连这些基本的细节都无法统一,那么C语言这种以“追求最高性能,把安全的责任推给程序员”为原则的语言,肯定会选择把大多数的细节规定成“undefined behaviour”、“unspecified behaviour”、“implementation-defined behaviour”什么的。这也就是C语言在各个平台上行为非常不同的根源了。也就是为什么用C语言写一个程序常常能在一个平台上跑,换一个平台就不能工作了。
老实说,这些undefined behaviour什么的,是很差劲的设计。这使得程序员无所适从。虽说初衷是好的:各个平台可以把int设定成尽可能快的类型。但后果就是程序员连“int有多大”都不知道。要是真想避免溢出,就不得不用保守的设计方法,不断地判断。
Java的设计原则就完全不一样:“写一次,到处跑”。Java里没有“未定义行为”。
- byte是8位,short是16位,int是32位,long是64位
- 有float和double类型。是用ieee754的。
- 整数加法溢出安静忽略高位;但是有Math.addExact提供抛出异常的加法。
- 除以0抛出java异常,可以捕获。
- 栈的增长方向程序员不可见,但参数求值永远是从左到右。
- 内存对齐是程序员不可见的,java保证int以下大小的成员变量,以及引用类型的成员变量的访问是原子的,但不保证long和double是。但volatile域永远是原子的。还有AtomicLong什么的。
- Java没有函数指针,甚至引用类型的大小也是程序员不可知的。但Java不允许在引用和整数之间转换。
- Java里空引用是一个特殊值null,同样,无法转换成整数。对null进行方法调用会抛出NullPointerException。
所以,程序员写Java程序的时候,很清楚每个语句、表达式会发生什么事,不用担心一个平台上能跑而另一个平台不能跑的问题。当然,高级的库(比如文件系统)还是有一些区别的。这就是另外一些问题了。比如目录的分隔符究竟是正斜杠/还是反斜杠\,linux和windows还不一致。换行符究竟是"\n"还是"\r\n",也没有达成一致。默认的字符编码是utf8还是什么,也没有达成一致。虽然有些编程语言(比如go和rust)把字符串规定成utf8的,但我认为是个很馊的主意。
但Java有可能遇到的问题就是,如果平台和Java虚拟机相差很大,某些操作实现起来效率不会很高。比如浮点数到整数的转换。如果浮点数是nan,在x86上的cvtsd2si指令会返回任意值,但Java规定返回0。所以Java虚拟机在编译java字节码的时候就不能直接编译成一条指令。但大多数情况,Java程序已经足够高效了(比C更高效其实也不意外。JVM的编译器很彪悍的)。在没有效率牺牲的情况下,给程序员提供一个可以依赖的平台,会让程序写起来舒服很多,也更可靠。
其实我觉得Java也不是最完美的。很多时候,人们需要的是数学上的“整数”的语义,而数学上的“整数”是无界的。Python的int就是无限大的。其实,利用现在的jit编译技术,可以很容易地将无穷精度的整数“特殊化”成效率最高的整数,这样还可以从根本上避免整数溢出问题。Java其实已经吃了亏:数组的下标是int型的,所以Java的数组大小永远无法超过2G个元素。但现在的个人电脑,16GiB的内存已经不稀罕了。最近,我也听到新闻说Ruby2.4也会像Python那样把默认整数变成无限精度的Integer而不是Fixnum。所以,我敢说,未来主流的编程语言,默认的整数类型会是无限精度的整数。
所以,我觉得,楼主的问题实质是:C语言太烂了,它没有尽到“高级语言”的责任,没有能提供对平台的抽象,使得程序员写一个能在各个平台上都能运行的程序,哪怕是最基本的整数运算程序,也是如此痛苦。
【 在 FromSixToTen 的大作中提到: 】
: 如果软件的基本框架和基本逻辑不变,那么软件从一个平台迁移到另一个平台,应该可以叫移植。而对于目前很多软件而言,当初设计时就已经考虑了跨平台。当然严格意义上讲,Windows XP、Windows 7之间的软件移植或适配或兼容也叫跨平台。
: 我个人觉得移植是一门很深的工程学,分简单移植和复杂移植,只要软件的核心功能和基本逻辑框架不变,把软件从其设计平台移动到其他平台运行就是软件移植。
: 个人观点,请暖神指点。 @wht
现在我又好奇另一件事情啦,你的这些字是复制粘贴的还是写得,如果写得那么真是辛苦啦。
【 在 nuanyangyang 的大作中提到: 】
: 怎么说呢,我觉得根本问题还是各个平台之间的差异性。如果像Java那样,所有平台上int都是32位,long都是64位,或者像Python那样所有的int都是无穷精度,那也就不必考虑移植、兼容、跨平台了。
: 然后就应该想想为什么各个平台上有差异了。C语言发明的那个年代,各个平台甚至对一些基本的细节都没有达成一致。比如
: - “字长”多大,有的是8位(红白机),有的是16(80286)、32(80386、armv6/v7)、64位(x86_64、aarch64),有的是28位(某个ibm的构架)什么的……
: ...................