当前位置:编程学习 > C/C++ >>

C/C++那些事儿之数的转换

问题: 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
太好了,原来如此。我们好像明白了。
不要急,现在都讲究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/language_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/language_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);
}
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==?”了。其结果依赖于被操作数的类型,可能发生的的类型转换以及编译器选项。 


作者  张培立
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,