BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #93743同步于 2016/10/19
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

[讨论]64位可移植性

shan10211865
2016/10/19镜像同步11 回复
默认(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指定长度的情况下*/
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
nuanyangyang机器人#1 · 2016/10/19
用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)在不同的平台上基本上没有可移植性。
NachtZ机器人#2 · 2016/10/19
stdint+1。前段时间刚刚被这个坑过。
shan10211865机器人#3 · 2016/10/19
嗯,我知道可以用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)在不同的平台上基本上没有可移植性。
shan10211865机器人#4 · 2016/10/19
如上。 【 在 NachtZ 的大作中提到: 】 : stdint+1。前段时间刚刚被这个坑过。
nuanyangyang机器人#5 · 2016/10/19
那就只能用宏来自己重新发明轮子了。用sizeof来自己定义定长整数类型吧。 【 在 shan10211865 的大作中提到: 】 : 嗯,我知道可以用stdint.h上面直接定义长度的整型,但是不能用 : 操作系统是自己扩展linux内核的私人平台,用C,所以不能用C++的标准 : 可移植性只需要考虑(u)long的变化,就是long(32)->long(64),int不变、pointer不变这种情况,不需要考虑迁移到win,OSX等,只需要考虑linux32位->linux64位
shan10211865机器人#6 · 2016/10/20
别人已经发明好了 其实我就是想先讨论一下上面的两个例子满不满足移植性要求 宏定义那个在32位下会截断? /*已验证64位ul宏可以无报错定义,64位的宏数据展开赋值给int只会传递低32位*/ 【 在 nuanyangyang 的大作中提到: 】 : 那就只能用宏来自己重新发明轮子了。用sizeof来自己定义定长整数类型吧。 :
FromSixToTen机器人#7 · 2016/10/21
如果软件的基本框架和基本逻辑不变,那么软件从一个平台迁移到另一个平台,应该可以叫移植。而对于目前很多软件而言,当初设计时就已经考虑了跨平台。当然严格意义上讲,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)在不同的平台上基本上没有可移植性。
nuanyangyang机器人#8 · 2016/10/21
怎么说呢,我觉得根本问题还是各个平台之间的差异性。如果像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
FromSixToTen机器人#9 · 2016/10/21
现在我又好奇另一件事情啦,你的这些字是复制粘贴的还是写得,如果写得那么真是辛苦啦。 【 在 nuanyangyang 的大作中提到: 】 : 怎么说呢,我觉得根本问题还是各个平台之间的差异性。如果像Java那样,所有平台上int都是32位,long都是64位,或者像Python那样所有的int都是无穷精度,那也就不必考虑移植、兼容、跨平台了。 : 然后就应该想想为什么各个平台上有差异了。C语言发明的那个年代,各个平台甚至对一些基本的细节都没有达成一致。比如 : - “字长”多大,有的是8位(红白机),有的是16(80286)、32(80386、armv6/v7)、64位(x86_64、aarch64),有的是28位(某个ibm的构架)什么的…… : ...................