C/C++中数的转换
副标题#e#
问题: d=1,-d==?
我们看看谜底会是什么样的:
—————————–
下面的代码的 输出是什么?
int main() {
char dt = ‘\1’;
long tdt;
tdt = -dt;
printf("%ld\n", tdt);
}
我的第一回响是这个输出应该是”-1“。 我想你也是这样认为的。然而假如在64位系统上输出是什么 呢?我期望也是”-1“。 我们看看是这样的吗。
让我们测试一下。
#xlc -q64 a.c – qlanglvl=extended
#./a.out
4294967295
!! 这里的输出是“4294967295” 而不是“-1”,怎么会这 样呢?
别急别急,大概是我们漏了什么?
在答复之前上面问题之前,我们看看下面代码段:
"char dt = ‘\1’; -dt;"
对付这个代码段,我们确认一下dt变量是有标记照旧没有标记的?C
我们看看C语言尺度怎么说的:
The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char.
也就是说尺度没有对char范例变量的标记做要求。我们在看看XL 编译器的文档 http://publib.boulder.ibm.com/infocenter/comphelp/v111v131/topic/com.ibm.xlc111.aix.doc/language _ref/ch.html
内里说:
By default, char behaves like an unsigned char. To change this default, you can use the -qchars option or the #pragma chars directive. See -qchars for more information.
看来XL编译器中,char默认是无标记的。我们可以用-qchars来改变这个默认行为。我们来测 试一下:
#xlc -q64 a.c -qlanglvl=extended -qchar=signed
#./a.out
-1
太好了,本来如 此。我们仿佛大白了。
#p#副标题#e#
不要急,此刻都考究Hold住。你真的大白了吗?大概还没有。 我们看另一个问题:
不消-qlanglvl=extended也可以获得“-1”,不管用不消-qchars, 为什么呢?如下:
————-
#xlc -q64 a.c
#./a.out
-1
————–
而且,下面的代码也打印“-1”,纵然利用- qlanglvl=extended:
————–
int main() {
unsigned char dt = ‘\1’;
long tdt =dt;
tdt = -tdt;
printf("%ld\n", tdt);
}
#xlc -q64 a.c -qlanglvl=extended ;./a.out
-1
————–
为什么下面的代码 的输出又成了 "4294967295"?
int main() {
unsigned dt = ‘\1’;
long tdt;
tdt = -dt;
printf("%ld\n", tdt);
}
这内里好像有一些深层的对象,我们来仔细看看下面几点:
* 减号操纵符的行为
* 整数晋升的 法则 ( integral promotion)
* 范例转换 (type cast)
########################################
我们一个一个来看:
1. 减号操纵符的行为: ISO C++ 尺度说
The result of the unary – operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.
因此减 号操纵符的运算功效范例依赖于操纵数被晋升之后的范例。
在XL编译器的文档中,也有雷同的说法:
http://publib.boulder.ibm.com/infocenter/comphelp/v111v131/topic/com.ibm.xlc111.aix.doc/langu age_ref/artnege.html
Unary minus operator – :The result has the same type as the operand after integral promotion.
2. 整数晋升的法则
在XL文档中我们看到下面的信息
http://publib.boulder.ibm.com/infocenter/comphelp/v111v131/topic/com.ibm.xlcpp111.aix.doc/lan guage_ref/integer_float_promotion.html?resultof=%22%70%72%6f%6d%6f%74%65%64%22%20%22%70%72%6f% 6d%6f%74%22%20
If an integer type other than wchar_t, bit field, and Boolean can be represented by the int type and its rank is lower than the rank of int, the integer type can be converted to the int type. Otherwise, the integer type can be converted to the unsigned int type.
同时我们留意到XL的下面说明:
*****************************************************************
-qupconv (C only)
Specifies whether the unsigned specification is preserved when integral promotions are performed.
Defaults
-qnoupconv for all language levels except classic or extended
-qupconv when the classic or extended language levels are in effect
***********************************************************
可以看出选项-qupconv(- qlanglvl=extended)影响了整数晋升时对标记位的处理惩罚行为。指定-qlanglvl=extended或-qupconv时保存符 号位举办整数晋升。
3. 我们知道在强制类换范例是标记位取决于方针范例。
由此,我们回过甚来看看 上面的代码:
———————-
int main() {
unsigned char dt = ‘\1’;
long tdt =dt; //范例强制转换 tdt 的仍然是”1“
tdt = -tdt; //功效范例仍然是 long, 因此功效是 -1
printf("%ld\n", tdt);
}
————————–
对付
int main() {
unsigned dt = ‘\1’;
long tdt;
tdt = -dt; ///==等价于 => (long)( (unsigned int) (-((unsigned int)u)) )
printf("%ld\n", tdt);
}
#p#分页标题#e#
dt范例是 unsigned int ,不需要 (按照上面的第2条)晋升, 因此 "-dt" 的范例仍然 是"unsigned int". 所以-dt 的值就是"0xFFFFFFFF" (在二进制上看),然后强 制转换成long范例并付给dt;因此 0x00000000FFFFFFFF的功效是4294967295。
对付
int main() {
unsigned char dt = ‘\1’;
long tdt;
tdt = -dt;
printf("%ld\n", tdt);
}
tdt = -dt; unsigned char首先需要晋升,晋升成为"unsigned int" 如 果-qupconv或-qlanglvl=extended;不然晋升成“int”
因此-qupconv/-qlanglvl=extended时:tdt=-dt 等价于to "(long)( (unsigned int) (-((unsigned int)td)) )" 。从而功效是4294967295
在 -qnoupconv(其他langlvl)时等价于"(long)( ( int) (-(( int)dt)) )" 功效是-1。
至此,我 们终于能过答复“d=1,-d==?”了。其功效依赖于被操纵数的范例,大概产生的的范例转换以及编译器选项。