Skip to content

数据类型

C语言提供了丰富的数据类型,包括基本数据类型、枚举类型、void类型和派生类型。本章将详细介绍C语言的数据类型。

数据类型分类

c
/*
 * C语言数据类型分类
 *
 * 基本类型:
 *   - 整型:char, short, int, long, long long
 *   - 浮点型:float, double, long double
 *
 * 枚举类型:
 *   - enum
 *
 * void类型:
 *   - void
 *
 * 派生类型:
 *   - 指针类型
 *   - 数组类型
 *   - 结构体类型
 *   - 联合体类型
 *   - 函数类型
 */

整型

整型类型

c
/*
 * 整型类型及其大小
 */

#include <stdio.h>
#include <limits.h>  /* 整型限制 */

int main(void)
{
    /* char 类型 */
    char c = 'A';
    unsigned char uc = 255;
    signed char sc = -128;
    
    printf("=== char 类型 ===\n");
    printf("char 大小: %zu 字节\n", sizeof(char));
    printf("char 范围: %d%d\n", CHAR_MIN, CHAR_MAX);
    printf("unsigned char 范围: 0 到 %d\n", UCHAR_MAX);
    
    /* short 类型 */
    short s = 1000;
    unsigned short us = 65535;
    
    printf("\n=== short 类型 ===\n");
    printf("short 大小: %zu 字节\n", sizeof(short));
    printf("short 范围: %d%d\n", SHRT_MIN, SHRT_MAX);
    printf("unsigned short 范围: 0 到 %u\n", USHRT_MAX);
    
    /* int 类型 */
    int i = 100000;
    unsigned int ui = 4294967295U;
    
    printf("\n=== int 类型 ===\n");
    printf("int 大小: %zu 字节\n", sizeof(int));
    printf("int 范围: %d%d\n", INT_MIN, INT_MAX);
    printf("unsigned int 范围: 0 到 %u\n", UINT_MAX);
    
    /* long 类型 */
    long l = 1000000L;
    unsigned long ul = 4294967295UL;
    
    printf("\n=== long 类型 ===\n");
    printf("long 大小: %zu 字节\n", sizeof(long));
    printf("long 范围: %ld%ld\n", LONG_MIN, LONG_MAX);
    printf("unsigned long 范围: 0 到 %lu\n", ULONG_MAX);
    
    /* long long 类型 (C99) */
    long long ll = 9223372036854775807LL;
    unsigned long long ull = 18446744073709551615ULL;
    
    printf("\n=== long long 类型 ===\n");
    printf("long long 大小: %zu 字节\n", sizeof(long long));
    printf("long long 范围: %lld%lld\n", LLONG_MIN, LLONG_MAX);
    printf("unsigned long long 范围: 0 到 %llu\n", ULLONG_MAX);
    
    return 0;
}

整数字面量

c
/*
 * 整数字面量(字面值)
 */

#include <stdio.h>

int main(void)
{
    /* 十进制 */
    int decimal = 100;
    printf("十进制: %d\n", decimal);
    
    /* 八进制(以0开头) */
    int octal = 0144;  /* 八进制144 = 十进制100 */
    printf("八进制0144 = 十进制%d\n", octal);
    
    /* 十六进制(以0x或0X开头) */
    int hexadecimal = 0x64;  /* 十六进制64 = 十进制100 */
    printf("十六进制0x64 = 十进制%d\n", hexadecimal);
    
    /* 二进制字面量 (C99不支持,GCC扩展) */
    /* int binary = 0b1100100; */  /* 二进制1100100 = 十进制100 */
    
    /* 类型后缀 */
    int i = 100;              /* int */
    unsigned int ui = 100U;   /* unsigned int */
    long l = 100L;            /* long */
    unsigned long ul = 100UL; /* unsigned long */
    long long ll = 100LL;     /* long long */
    
    printf("int: %d\n", i);
    printf("unsigned: %u\n", ui);
    printf("long: %ld\n", l);
    printf("unsigned long: %lu\n", ul);
    printf("long long: %lld\n", ll);
    
    return 0;
}

有符号与无符号

c
/*
 * 有符号与无符号整数
 */

#include <stdio.h>
#include <limits.h>

int main(void)
{
    /* 有符号整数可以表示正数和负数 */
    signed int si = -100;
    printf("有符号整数: %d\n", si);
    
    /* 无符号整数只能表示非负数 */
    unsigned int ui = 100;
    printf("无符号整数: %u\n", ui);
    
    /* 溢出行为 */
    unsigned int max = UINT_MAX;
    printf("无符号最大值: %u\n", max);
    printf("最大值+1: %u\n", max + 1);  /* 回绕到0 */
    
    signed int smin = INT_MIN;
    printf("有符号最小值: %d\n", smin);
    printf("最小值-1: %d\n", smin - 1);  /* 未定义行为或回绕 */
    
    /* 混合运算 */
    int a = -1;
    unsigned int b = 1;
    
    /* 注意:有符号和无符号比较时,有符号会被转换为无符号 */
    if (a < b) {
        printf("-1 < 1 (预期结果)\n");
    } else {
        printf("-1 >= 1 (意外结果!)\n");  /* 这会输出! */
    }
    
    /* 正确的比较方式 */
    if ((int)a < (int)b) {
        printf("强制转换后: -1 < 1\n");
    }
    
    return 0;
}

浮点型

浮点类型

c
/*
 * 浮点类型及其大小
 */

#include <stdio.h>
#include <float.h>  /* 浮点型限制 */

int main(void)
{
    /* float - 单精度浮点数 */
    float f = 3.14159f;
    printf("=== float 类型 ===\n");
    printf("float 大小: %zu 字节\n", sizeof(float));
    printf("float 最小正值: %e\n", FLT_MIN);
    printf("float 最大值: %e\n", FLT_MAX);
    printf("float 精度: %d\n", FLT_DIG);
    printf("示例值: %.6f\n", f);
    
    /* double - 双精度浮点数 */
    double d = 3.14159265358979;
    printf("\n=== double 类型 ===\n");
    printf("double 大小: %zu 字节\n", sizeof(double));
    printf("double 最小正值: %e\n", DBL_MIN);
    printf("double 最大值: %e\n", DBL_MAX);
    printf("double 精度: %d\n", DBL_DIG);
    printf("示例值: %.15f\n", d);
    
    /* long double - 扩展精度浮点数 */
    long double ld = 3.14159265358979323846L;
    printf("\n=== long double 类型 ===\n");
    printf("long double 大小: %zu 字节\n", sizeof(long double));
    printf("示例值: %.18Lf\n", ld);
    
    return 0;
}

浮点数字面量

c
/*
 * 浮点数字面量
 */

#include <stdio.h>

int main(void)
{
    /* 小数形式 */
    double d1 = 3.14;
    double d2 = .5;      /* 0.5 */
    double d3 = 5.;      /* 5.0 */
    
    printf("小数形式: %f, %f, %f\n", d1, d2, d3);
    
    /* 指数形式(科学计数法) */
    double e1 = 1.5e3;   /* 1.5 × 10³ = 1500.0 */
    double e2 = 2.5E-2;  /* 2.5 × 10⁻² = 0.025 */
    
    printf("指数形式: %f, %f\n", e1, e2);
    printf("科学计数法: %e, %e\n", e1, e2);
    
    /* 类型后缀 */
    float f = 3.14f;           /* float */
    double d = 3.14;           /* double(默认) */
    long double ld = 3.14L;    /* long double */
    
    printf("float: %f\n", f);
    printf("double: %f\n", d);
    printf("long double: %Lf\n", ld);
    
    /* 特殊浮点值 */
    double positive_inf = 1.0 / 0.0;
    double negative_inf = -1.0 / 0.0;
    double nan_value = 0.0 / 0.0;
    
    printf("\n特殊值:\n");
    printf("正无穷: %f\n", positive_inf);
    printf("负无穷: %f\n", negative_inf);
    printf("非数(NaN): %f\n", nan_value);
    
    return 0;
}

浮点数精度问题

c
/*
 * 浮点数精度问题
 */

#include <stdio.h>
#include <math.h>

int main(void)
{
    /* 精度丢失 */
    float f = 0.1f;
    printf("0.1f 的实际值: %.20f\n", f);
    
    /* 累加误差 */
    float sum = 0.0f;
    for (int i = 0; i < 10; i++) {
        sum += 0.1f;
    }
    printf("10个0.1相加: %.20f\n", sum);
    printf("是否等于1.0: %s\n", sum == 1.0f ? "是" : "否");
    
    /* 正确的比较方式 */
    float epsilon = 1e-6f;
    if (fabs(sum - 1.0f) < epsilon) {
        printf("使用误差比较: 近似等于1.0\n");
    }
    
    /* 不同精度的比较 */
    float f_val = 0.123456789f;
    double d_val = 0.123456789;
    
    printf("\nfloat: %.15f\n", f_val);
    printf("double: %.15f\n", d_val);
    
    /* 避免精度问题的建议 */
    printf("\n=== 避免精度问题的建议 ===\n");
    printf("1. 使用double而不是float\n");
    printf("2. 避免直接比较浮点数\n");
    printf("3. 使用误差范围比较\n");
    printf("4. 考虑使用整数运算\n");
    
    return 0;
}

字符型

char类型

c
/*
 * char类型
 */

#include <stdio.h>
#include <limits.h>

int main(void)
{
    /* char 可以存储单个字符 */
    char ch1 = 'A';
    char ch2 = 65;      /* 65是'A'的ASCII码 */
    char ch3 = '\x41';  /* 十六进制表示 */
    char ch4 = '\101';  /* 八进制表示 */
    
    printf("字符: %c, %c, %c, %c\n", ch1, ch2, ch3, ch4);
    printf("ASCII码: %d, %d, %d, %d\n", ch1, ch2, ch3, ch4);
    
    /* char 的本质是整数 */
    char letter = 'A';
    printf("\n字符运算:\n");
    printf("'A' + 1 = %c\n", letter + 1);  /* 'B' */
    printf("'A' - 'A' + 'a' = %c\n", letter - 'A' + 'a');  /* 'a' */
    
    /* 判断字符类型 */
    char c = '5';
    if (c >= '0' && c <= '9') {
        printf("%c 是数字\n", c);
    }
    
    c = 'A';
    if (c >= 'A' && c <= 'Z') {
        printf("%c 是大写字母\n", c);
    }
    
    c = 'a';
    if (c >= 'a' && c <= 'z') {
        printf("%c 是小写字母\n", c);
    }
    
    /* signed char vs unsigned char */
    signed char sc = -10;
    unsigned char uc = 200;
    
    printf("\nsigned char: %d\n", sc);
    printf("unsigned char: %u\n", uc);
    
    return 0;
}

ASCII字符集

c
/*
 * ASCII字符集
 */

#include <stdio.h>

int main(void)
{
    printf("=== ASCII字符表 ===\n\n");
    
    /* 控制字符 (0-31) */
    printf("控制字符:\n");
    printf("NULL: \\0 (ASCII 0)\n");
    printf("换行: \\n (ASCII 10)\n");
    printf("回车: \\r (ASCII 13)\n");
    printf("制表: \\t (ASCII 9)\n");
    
    /* 可打印字符 (32-126) */
    printf("\n可打印字符:\n");
    
    /* 数字 0-9 */
    printf("数字: ");
    for (char c = '0'; c <= '9'; c++) {
        printf("%c ", c);
    }
    printf("\n");
    
    /* 大写字母 A-Z */
    printf("大写字母: ");
    for (char c = 'A'; c <= 'Z'; c++) {
        printf("%c ", c);
    }
    printf("\n");
    
    /* 小写字母 a-z */
    printf("小写字母: ");
    for (char c = 'a'; c <= 'z'; c++) {
        printf("%c ", c);
    }
    printf("\n");
    
    /* 特殊字符 */
    printf("\n特殊字符:\n");
    printf("空格: ' ' (ASCII 32)\n");
    printf("感叹号: '!' (ASCII 33)\n");
    printf("双引号: '\"' (ASCII 34)\n");
    printf("单引号: '\\'' (ASCII 39)\n");
    printf("星号: '*' (ASCII 42)\n");
    printf("加号: '+' (ASCII 43)\n");
    printf("减号: '-' (ASCII 45)\n");
    printf("斜杠: '/' (ASCII 47)\n");
    
    /* 打印完整ASCII表 */
    printf("\n完整ASCII表(可打印字符):\n");
    for (int i = 32; i <= 126; i++) {
        printf("%3d:%c ", i, (char)i);
        if ((i - 31) % 10 == 0) {
            printf("\n");
        }
    }
    printf("\n");
    
    return 0;
}

void类型

c
/*
 * void类型
 */

#include <stdio.h>
#include <stdlib.h>

/* void作为函数返回类型 */
void print_message(void)
{
    printf("这是一个无返回值的函数\n");
}

/* void作为函数参数 */
int get_number(void)  /* 明确表示函数不接受参数 */
{
    return 42;
}

/* void指针可以指向任何类型 */
void print_value(void *ptr, char type)
{
    switch (type) {
        case 'i':
            printf("整数: %d\n", *(int*)ptr);
            break;
        case 'f':
            printf("浮点数: %f\n", *(float*)ptr);
            break;
        case 'c':
            printf("字符: %c\n", *(char*)ptr);
            break;
    }
}

int main(void)
{
    /* void作为函数返回类型 */
    print_message();
    
    /* void作为函数参数 */
    int num = get_number();
    printf("获取的数字: %d\n", num);
    
    /* void指针 */
    int i = 10;
    float f = 3.14f;
    char c = 'X';
    
    void *ptr;
    
    ptr = &i;
    printf("void指针指向整数: %d\n", *(int*)ptr);
    
    ptr = &f;
    printf("void指针指向浮点数: %f\n", *(float*)ptr);
    
    ptr = &c;
    printf("void指针指向字符: %c\n", *(char*)ptr);
    
    /* 使用void指针函数 */
    print_value(&i, 'i');
    print_value(&f, 'f');
    print_value(&c, 'c');
    
    return 0;
}

类型转换

隐式类型转换

c
/*
 * 隐式类型转换(自动转换)
 */

#include <stdio.h>

int main(void)
{
    /* 整型提升 */
    char c = 'A';
    short s = 100;
    
    /* char和short在运算时自动提升为int */
    int result = c + s;
    printf("char + short = int: %d\n", result);
    
    /* 算术转换 */
    int i = 5;
    float f = 2.5f;
    
    /* int和float运算时,int转换为float */
    float f_result = i + f;
    printf("int + float = float: %f\n", f_result);
    
    /* 赋值转换 */
    double d = 3.14159;
    float f2 = d;  /* double转换为float,可能丢失精度 */
    int i2 = d;    /* double转换为int,截断小数部分 */
    
    printf("double -> float: %f\n", f2);
    printf("double -> int: %d\n", i2);
    
    /* 类型转换等级(从低到高) */
    printf("\n类型转换等级:\n");
    printf("int -> unsigned int -> long -> unsigned long -> ");
    printf("long long -> unsigned long long -> float -> double -> long double\n");
    
    return 0;
}

显式类型转换

c
/*
 * 显式类型转换(强制转换)
 */

#include <stdio.h>

int main(void)
{
    /* 基本类型转换 */
    double d = 3.7;
    
    /* 强制转换为int(截断小数) */
    int i = (int)d;
    printf("double %f -> int %d\n", d, i);
    
    /* 强制转换用于运算 */
    int a = 5, b = 2;
    
    /* 整数除法 */
    int int_div = a / b;
    printf("整数除法: %d / %d = %d\n", a, b, int_div);
    
    /* 浮点除法(强制转换) */
    float float_div = (float)a / b;
    printf("浮点除法: %d / %d = %f\n", a, b, float_div);
    
    /* 指针类型转换 */
    int num = 0x41424344;
    
    /* 将int指针转换为char指针 */
    char *ptr = (char*)&num;
    printf("\nint 0x%x 的字节表示:\n", num);
    for (int j = 0; j < 4; j++) {
        printf("字节%d: %c (0x%02x)\n", j, ptr[j], (unsigned char)ptr[j]);
    }
    
    /* void指针转换 */
    void *vptr = &num;
    int *iptr = (int*)vptr;
    printf("\nvoid指针转换: %d\n", *iptr);
    
    /* 注意事项 */
    printf("\n=== 类型转换注意事项 ===\n");
    printf("1. 浮点转整数会截断小数\n");
    printf("2. 大类型转小类型可能丢失数据\n");
    printf("3. 指针转换要确保类型兼容\n");
    printf("4. 避免不必要的类型转换\n");
    
    return 0;
}

sizeof运算符

c
/*
 * sizeof运算符
 */

#include <stdio.h>

int main(void)
{
    /* 基本类型的sizeof */
    printf("=== 基本类型大小 ===\n");
    printf("char: %zu 字节\n", sizeof(char));
    printf("short: %zu 字节\n", sizeof(short));
    printf("int: %zu 字节\n", sizeof(int));
    printf("long: %zu 字节\n", sizeof(long));
    printf("long long: %zu 字节\n", sizeof(long long));
    printf("float: %zu 字节\n", sizeof(float));
    printf("double: %zu 字节\n", sizeof(double));
    printf("long double: %zu 字节\n", sizeof(long double));
    
    /* 变量的sizeof */
    int arr[10];
    char str[] = "Hello";
    
    printf("\n=== 变量大小 ===\n");
    printf("arr数组: %zu 字节\n", sizeof(arr));
    printf("arr元素个数: %zu\n", sizeof(arr) / sizeof(arr[0]));
    printf("str数组: %zu 字节\n", sizeof(str));  /* 包含'\0' */
    
    /* sizeof是编译时运算符 */
    printf("\n=== sizeof特性 ===\n");
    
    /* sizeof的结果类型是size_t */
    printf("sizeof返回size_t类型\n");
    printf("size_t大小: %zu 字节\n", sizeof(size_t));
    
    /* sizeof与表达式 */
    int x = 10;
    printf("sizeof(x): %zu\n", sizeof(x));
    printf("sizeof(x + 1): %zu\n", sizeof(x + 1));  /* 表达式不计算 */
    printf("x的值仍然是: %d\n", x);
    
    return 0;
}

typedef类型定义

c
/*
 * typedef类型定义
 */

#include <stdio.h>
#include <stdint.h>  /* 固定宽度整数类型 */

/* 定义类型别名 */
typedef unsigned char byte;
typedef unsigned int uint;
typedef char* String;

/* 定义结构体别名 */
typedef struct {
    int x;
    int y;
} Point;

/* 定义函数指针别名 */
typedef int (*Operation)(int, int);

int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }

int main(void)
{
    /* 使用自定义类型 */
    byte b = 255;
    uint u = 100;
    String s = "Hello";
    
    printf("byte: %u\n", b);
    printf("uint: %u\n", u);
    printf("String: %s\n", s);
    
    /* 使用结构体别名 */
    Point p1 = {10, 20};
    Point p2 = {30, 40};
    
    printf("\nPoint p1: (%d, %d)\n", p1.x, p1.y);
    printf("Point p2: (%d, %d)\n", p2.x, p2.y);
    
    /* 使用函数指针别名 */
    Operation op;
    
    op = add;
    printf("\n加法: %d\n", op(10, 5));
    
    op = subtract;
    printf("减法: %d\n", op(10, 5));
    
    /* 固定宽度整数类型 */
    printf("\n=== 固定宽度整数类型 ===\n");
    int8_t i8 = 127;
    int16_t i16 = 32767;
    int32_t i32 = 2147483647;
    int64_t i64 = 9223372036854775807LL;
    
    uint8_t u8 = 255;
    uint16_t u16 = 65535;
    uint32_t u32 = 4294967295U;
    uint64_t u64 = 18446744073709551615ULL;
    
    printf("int8_t: %d\n", i8);
    printf("int16_t: %d\n", i16);
    printf("int32_t: %d\n", i32);
    printf("int64_t: %lld\n", i64);
    printf("uint8_t: %u\n", u8);
    printf("uint16_t: %u\n", u16);
    printf("uint32_t: %u\n", u32);
    printf("uint64_t: %llu\n", u64);
    
    return 0;
}

小结

本章学习了:

  • 数据类型分类:基本类型、枚举类型、void类型、派生类型
  • 整型:char、short、int、long、long long 及其有符号/无符号变体
  • 浮点型:float、double、long double 及其精度问题
  • 字符型:char类型和ASCII字符集
  • void类型:函数返回值、参数、通用指针
  • 类型转换:隐式转换和显式转换
  • sizeof运算符:获取类型和变量大小
  • typedef:定义类型别名

下一章,我们将学习运算符,了解C语言中的各种运算操作。