Skip to content

C 类型转换

类型转换 (Type casting)(或称类型转换,type conversion)是将一个值从一种数据类型转换为另一种数据类型的过程。C 语言允许隐式(自动)和显式(手动)类型转换。

隐式类型转换 (Implicit Type Conversion)(强制转换 Coercion)

Section titled “隐式类型转换 (Implicit Type Conversion)(强制转换 Coercion)”

当表达式中混合使用不同数据类型时,编译器会自动执行隐式转换,通常是为了避免数据丢失,通过转换为“更宽”或排名更高的数据类型。

主要的隐式转换规则:

  • 整型提升 (Integer Promotion): 小于 int 或 unsigned int 的类型(如 char、short、_Bool、位字段)在算术运算前会自动提升为 int 或 unsigned int。
  • 常规算术转换 (Usual Arithmetic Conversions): 当操作涉及不同算术类型的操作数时,编译器会根据优先级将它们转换为通用类型。一般规则是转换为排名最高的类型。

常规算术转换的优先级(简化版):

Section titled “常规算术转换的优先级(简化版):”
  1. 如果任一操作数是 long double,则将另一操作数转换为 long double。
  2. 否则,如果任一操作数是 double,则将另一操作数转换为 double。
  3. 否则,如果任一操作数是 float,则将另一操作数转换为 float。
  4. 否则(两个操作数都是整型):首先执行整型提升。
  5. 如果类型仍然不同:
    • 如果两者都是有符号或都是无符号,则将低排名的类型转换为高排名的类型(int < long < long long)。
    • 如果无符号类型的排名 >= 有符号类型,则将有符号类型转换为无符号类型。
    • 如果有符号类型可以表示无符号类型的所有值,则将无符号类型转换为有符号类型。
    • 否则,将两者都转换为有符号类型的无符号版本。
#include <stdio.h>
int main(void) {
short s = 100;
char c = 5;
int result;
// s 和 c 在加法前被提升为 'int'
result = s + c;
printf("Result (short + char): %d\n", result); // Output: 105
return 0;
}
#include <stdio.h>
int main(void) {
int i = 10;
float f = 5.5f;
double d = 0.25;
double result;
// 在 i + f 中:i 被转换为 float,结果是 float。
// 然后 (float result) + d:float 结果被转换为 double。
result = i + f + d; // 通用类型变为 double
printf("Result (int + float + double): %lf\n", result); // Output: 15.750000
return 0;
}

显式类型转换 (Explicit Type Conversion)(强制类型转换 Casting)

Section titled “显式类型转换 (Explicit Type Conversion)(强制类型转换 Casting)”

你可以使用强制转换运算符 (cast operator) 显式地强制进行转换:(type_name) expression。

expression 的值被转换为指定的 type_name。显式强制转换在以下情况下是必要的:

  • 你想覆盖隐式转换规则(例如,从整数强制进行浮点除法)。
  • 你需要转换指针类型(使用时务必小心!)。
  • 你想使潜在的数据丢失转换变得显式,以提高清晰度。
#include <stdio.h>
int main(void) {
int sum = 17;
int count = 5;
double mean_implicit; // 隐式转换发生在除法 *之后*
double mean_explicit; // 显式强制转换发生在除法 *之前*
// 隐式转换:sum / count 是整型除法 (17 / 5 = 3)
// 然后整型 3 被转换为 double 3.0
mean_implicit = sum / count;
// 显式强制转换:(double)sum 首先将 sum 转换为 17.0。
// 然后 17.0 / 5 执行浮点除法。
mean_explicit = (double)sum / count;
printf("Mean (implicit conversion after int division): %.6f\n", mean_implicit); // Output: 3.000000
printf("Mean (explicit cast before division) : %.6f\n", mean_explicit); // Output: 3.400000
return 0;
}

强制转换运算符 (double) 的优先级高于除法运算符 /,因此 sum 会首先被转换。

强制转换指针可能在某些情况下是必要的(例如,与返回 void* 的 malloc 一起使用),但如果类型不兼容则非常危险。

#include <stdlib.h>
int main(void) {
// malloc 返回 void*,必须强制转换为所需的指针类型
int *int_ptr = (int*)malloc(10 * sizeof(int));
if (!int_ptr) return 1;
char *char_ptr = NULL;
// 如果对齐/大小错误,这是潜在的危险强制转换
// char_ptr = (char*)int_ptr;
free(int_ptr);
return 0;
}
  • 信息丢失 (Loss of Information): 从更宽的类型强制转换为更窄的类型(例如,double 到 int,long 到 short)可能会截断值或导致溢出。
  • 未定义行为 (Undefined Behavior): 强制转换不兼容的指针类型并解引用可能会违反对齐规则或错误解释数据,导致程序崩溃或结果不正确。
  • 有符号/无符号问题 (Signed/Unsigned Issues): 在有符号和无符号类型之间进行转换可能会改变位模式的解释方式,特别是对于负数。

虽然隐式转换会自动发生,但当转换是有意为之,特别是如果可能涉及数据丢失或表示更改时,使用显式强制转换 (type_name) 通常被认为是良好的编程习惯,可以使意图对其他读者更清晰。