C&C++快速入门

5、基础数据类型

1、课程目标

  • 掌握C/C++中的基础数据类型
  • 理解不同类型的内存占用和取值范围
  • 掌握类型转换的规则和陷阱
  • 了解Windows API中常用的类型定义

2、名词解释

术语 英文 说明
整型 Integer 存储整数的数据类型
浮点型 Floating Point 存储小数的数据类型
字符型 Character 存储单个字符
布尔型 Boolean 存储真/假值
有符号 Signed 可表示正负数
无符号 Unsigned 只能表示非负数
溢出 Overflow 超出类型表示范围
隐式转换 Implicit Conversion 编译器自动进行的类型转换
显式转换 Explicit Conversion 程序员手动指定的类型转换
sizeof - 获取类型或变量字节大小的运算符

3、Windows API常用类型

Windows类型 对应C类型 大小
BYTE unsigned char 1字节
WORD unsigned short 2字节
DWORD unsigned long 4字节
QWORD unsigned __int64 8字节
BOOL int 4字节
CHAR char 1字节
WCHAR wchar_t 2字节
LPSTR char* 指针
LPWSTR wchar_t* 指针
LPVOID void* 指针
HANDLE void* 指针
SIZE_T 平台相关 4/8字节

4、代码实现

1. 基础类型大小与范围

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

int main() {
    printf("=== C语言基础类型 ===\n\n");
    
    // 整型
    printf("【整型】\n");
    printf("char:        %d字节, 范围: %d ~ %d\n", 
           (int)sizeof(char), CHAR_MIN, CHAR_MAX);
    printf("short:       %d字节, 范围: %d ~ %d\n", 
           (int)sizeof(short), SHRT_MIN, SHRT_MAX);
    printf("int:         %d字节, 范围: %d ~ %d\n", 
           (int)sizeof(int), INT_MIN, INT_MAX);
    printf("long:        %d字节, 范围: %ld ~ %ld\n", 
           (int)sizeof(long), LONG_MIN, LONG_MAX);
    printf("long long:   %d字节, 范围: %lld ~ %lld\n", 
           (int)sizeof(long long), LLONG_MIN, LLONG_MAX);
    
    // 无符号整型
    printf("\n【无符号整型】\n");
    printf("unsigned char:      范围: 0 ~ %u\n", UCHAR_MAX);
    printf("unsigned short:     范围: 0 ~ %u\n", USHRT_MAX);
    printf("unsigned int:       范围: 0 ~ %u\n", UINT_MAX);
    printf("unsigned long long: 范围: 0 ~ %llu\n", ULLONG_MAX);
    
    // 浮点型
    printf("\n【浮点型】\n");
    printf("float:       %d字节, 精度: %d位, 范围: %e ~ %e\n", 
           (int)sizeof(float), FLT_DIG, FLT_MIN, FLT_MAX);
    printf("double:      %d字节, 精度: %d位, 范围: %e ~ %e\n", 
           (int)sizeof(double), DBL_DIG, DBL_MIN, DBL_MAX);
    
    // Windows类型
    printf("\n【Windows类型】\n");
    printf("BYTE:    %d字节\n", (int)sizeof(BYTE));
    printf("WORD:    %d字节\n", (int)sizeof(WORD));
    printf("DWORD:   %d字节\n", (int)sizeof(DWORD));
    printf("BOOL:    %d字节\n", (int)sizeof(BOOL));
    printf("LPVOID:  %d字节\n", (int)sizeof(LPVOID));
    printf("SIZE_T:  %d字节\n", (int)sizeof(SIZE_T));
    printf("HANDLE:  %d字节\n", (int)sizeof(HANDLE));
    
    return 0;
}

2. 类型转换示例

#include <stdio.h>

int main() {
    printf("=== 类型转换演示 ===\n\n");
    
    // 1. 整数溢出
    printf("【整数溢出】\n");
    unsigned char uc = 255;
    printf("unsigned char = 255\n");
    uc = uc + 1;  // 溢出
    printf("加1后: %d (溢出回绕到0)\n", uc);
    
    signed char sc = 127;
    printf("\nsigned char = 127\n");
    sc = sc + 1;  // 溢出
    printf("加1后: %d (溢出变为负数)\n", sc);
    
    // 2. 有符号与无符号比较陷阱
    printf("\n【有符号vs无符号陷阱】\n");
    int a = -1;
    unsigned int b = 1;
    if (a < b) {
        printf("-1 < 1 (正确)\n");
    } else {
        printf("-1 >= 1 (错误!因为-1被转为无符号大数)\n");
    }
    printf("实际比较: %u vs %u\n", (unsigned int)a, b);
    
    // 3. 浮点精度问题
    printf("\n【浮点精度问题】\n");
    float f1 = 0.1f;
    float f2 = 0.2f;
    float f3 = f1 + f2;
    printf("0.1 + 0.2 = %.20f (不精确!)\n", f3);
    
    // 正确的浮点比较方式
    float epsilon = 0.00001f;
    if (f3 - 0.3f < epsilon && 0.3f - f3 < epsilon) {
        printf("使用epsilon比较: 0.1 + 0.2 ≈ 0.3\n");
    }
    
    // 4. 强制类型转换
    printf("\n【强制类型转换】\n");
    int intVal = 65;
    printf("int值 %d 转为char: '%c'\n", intVal, (char)intVal);
    
    double pi = 3.14159;
    printf("double值 %.5f 转为int: %d\n", pi, (int)pi);
    
    return 0;
}

3. 指针与类型大小

#include <stdio.h>
#include <windows.h>

int main() {
    printf("=== 指针类型演示 ===\n\n");
    
    // 所有指针大小相同(取决于平台)
    printf("【指针大小】\n");
    printf("char*:    %d字节\n", (int)sizeof(char*));
    printf("int*:     %d字节\n", (int)sizeof(int*));
    printf("double*:  %d字节\n", (int)sizeof(double*));
    printf("void*:    %d字节\n", (int)sizeof(void*));
    
    #ifdef _WIN64
    printf("\n当前编译: 64位 (指针8字节)\n");
    #else
    printf("\n当前编译: 32位 (指针4字节)\n");
    #endif
    
    // 指针运算与类型的关系
    printf("\n【指针运算】\n");
    int arr[5] = {10, 20, 30, 40, 50};
    int* p = arr;
    
    printf("数组地址: %p\n", (void*)p);
    printf("p+0 = %p, 值 = %d\n", (void*)(p+0), *(p+0));
    printf("p+1 = %p, 值 = %d\n", (void*)(p+1), *(p+1));
    printf("地址差: %d字节 (=sizeof(int))\n", 
           (int)((char*)(p+1) - (char*)p));
    
    return 0;
}

4、课后作业

4.1、作业1:类型大小测试

编写程序,打印以下类型在你的系统上的大小:

  • size_t, ptrdiff_t, intptr_t, uintptr_t
  • wchar_t, char16_t, char32_t

4.2、作业2:溢出检测

实现一个安全的加法函数,能够检测整数溢出:

BOOL SafeAdd(int a, int b, int* result);
// 返回TRUE表示成功,FALSE表示溢出

4.3、作业3:类型转换陷阱

解释以下代码的输出结果:

char c = 200;
printf("%d\n", c);  // 输出什么?为什么?

unsigned int u = 0;
u = u - 1;
printf("%u\n", u);  // 输出什么?为什么?