<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear:both;"><a id="id2757924"></a>3. 类型转换</h2>
</div>
</div>
</div>
<p>如果有人问C语法规则中最复杂的是哪一部分,我一定会说是类型转换。从上面两节可以看出,有符号、无符号整数和浮点数加起来有那么多种类型,每两种类型之间都要定义一个转换规则,转换规则的数量自然很庞大,更何况由于各种体系结构对于整数和浮点数的实现很不相同,很多类型转换的情况都是C标准未做明确规定的阴暗角落。虽然我们写代码时不会故意去触碰这些阴暗角落,但有时候会不小心犯错,所以了解一些未明确规定的情况还是有必要的,可以在出错时更容易分析错误原因。本节分成几小节,首先介绍哪些情况下会发生类型转换,会把什么类型转成什么类型,然后介绍编译器如何处理这样的类型转换。</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="id2757955"></a>3.1. Integer Promotion</h3>
</div>
</div>
</div>
<p>在一个表达式中,凡是可以使用<code class="literal">int</code>或<code class="literal">unsigned int</code>类型做右值的地方也都可以使用有符号或无符号的<code class="literal">char</code>型、<code class="literal">short</code>型和Bit-field。如果原始类型的取值范围都能用<code class="literal">int</code>型表示,则其类型被提升为<code class="literal">int</code>,如果原始类型的取值范围用<code class="literal">int</code>型表示不了,则提升为<code class="literal">unsigned
int</code>型,这称为Integer Promotion<a class="indexterm" id="id2758017"></a>。做Integer Promotion只影响上述几种类型的值,对其它类型无影响。C99规定Integer Promotion适用于以下几种情况:</p>
<p>1、如果一个函数的形参类型未知,例如使用了Old Style C风格的函数声明(详见<a class="xref" href="https://blog.csdn.net/jeffreyst_zb/article/details/ch03s02.html#func.ourfirstfunc" rel="nofollow">第 2 节 “自定义函数”</a>),或者函数的参数列表中有...,那么调用函数时要对相应的实参做Integer Promotion,此外,相应的实参如果是<code class="literal">float</code>型的也要被提升为<code class="literal">double</code>型,这条规则称为Default
Argument Promotion<a class="indexterm" id="id2758055"></a>。我们知道<code class="literal">printf</code>的参数列表中有<code class="literal">...</code>,除了第一个形参之外,其它形参的类型都是未知的,比如有这样的代码:</p>
<pre class="programlisting">char ch = 'A';
printf("%c", ch);</pre>
<p><code class="literal">ch</code>要被提升为<code class="literal">int</code>型之后再传给<code class="literal">printf</code>。</p>
<p>2、算术运算中的类型转换。有符号或无符号的<code class="literal">char</code>型、<code class="literal">short</code>型和Bit-field在做算术运算之前首先要做Integer Promotion,然后才能参与计算。例如:</p>
<pre class="programlisting">unsigned char c1 = 255, c2 = 2;
int n = c1 + c2;</pre>
<p>计算表达式<code class="literal">c1 + c2</code>的过程其实是先把<code class="literal">c1</code>和<code class="literal">c2</code>提升为<code class="literal">int</code>型然后再相加(<code class="literal">unsigned char</code>的取值范围是0~255,完全可以用<code class="literal">int</code>表示,所以提升为<code class="literal">int</code>就可以了,不需要提升为<code class="literal">unsigned
int</code>),整个表达式的值也是<code class="literal">int</code>型,最后的结果是257。假如没有这个提升的过程,<code class="literal">c1 + c2</code>就溢出了,溢出会得到什么结果是Undefined,在大多数平台上会把进位截掉,得到的结果应该是1。</p>
<p>除了+号之外还有哪些运算符在计算之前需要做Integer Promotion呢?我们在下一小节先介绍Usual Arithmetic Conversion规则,然后再解答这个问题。</p>
</div>
<div class="sect2" lang="zh-cn">
<div class="titlepage">
<div>
<div>
<h3 class="title"><a id="id2758200"></a>3.2. Usual Arithmetic Conversion</h3>
</div>
</div>
</div>
<p>两个算术类型的操作数做算术运算,比如<code class="literal">a + b</code>,如果两边操作数的类型不同,编译器会自动做类型转换,使两边类型相同之后才做运算,这称为Usual Arithmetic Conversion<a class="indexterm" id="id2758216"></a>。转换规则如下:</p>
<div class="orderedlist">
<ol type="1"><li>
<p>如果有一边的类型是<code class="literal">long double</code>,则把另一边也转成<code class="literal">long double</code>。</p>
</li><li>
<p>否则,如果有一边的类型是<code class="literal">double</code>,则把另一边也转成<code class="literal">double</code>。</p>
</li><li>
<p>否则,如果有一边的类型是<code class="literal">float</code>,则把另一边也转成<code class="literal">float</code>。</p>
</li><li>
<p>否则,两边应该都是整型,首先按上一小节讲过的规则对<code class="literal">a</code>和<code class="literal">b</code>做Integer Promotion,然后如果 |
|