Skip to content

C++ 修饰符类型

概述

修饰符(Modifiers)是C++中用于修改基本数据类型特性的关键字。它们可以改变变量的符号性、大小、存储位置等属性。理解和正确使用修饰符对于编写高效、正确的C++程序至关重要。

🔢 符号修饰符

signed和unsigned

cpp
#include <iostream>
#include <limits>

int main() {
    // signed修饰符(默认情况)
    signed char s_char = -128;
    signed int s_int = -2147483648;
    signed short s_short = -32768;
    
    // unsigned修饰符
    unsigned char u_char = 255;
    unsigned int u_int = 4294967295U;
    unsigned short u_short = 65535;
    
    // 输出范围信息
    std::cout << "=== signed类型范围 ===" << std::endl;
    std::cout << "signed char: " 
              << static_cast<int>(std::numeric_limits<signed char>::min()) 
              << " 到 " 
              << static_cast<int>(std::numeric_limits<signed char>::max()) << std::endl;
    
    std::cout << "signed int: " 
              << std::numeric_limits<signed int>::min() 
              << " 到 " 
              << std::numeric_limits<signed int>::max() << std::endl;
    
    std::cout << "\n=== unsigned类型范围 ===" << std::endl;
    std::cout << "unsigned char: " 
              << static_cast<int>(std::numeric_limits<unsigned char>::min()) 
              << " 到 " 
              << static_cast<int>(std::numeric_limits<unsigned char>::max()) << std::endl;
    
    std::cout << "unsigned int: " 
              << std::numeric_limits<unsigned int>::min() 
              << " 到 " 
              << std::numeric_limits<unsigned int>::max() << std::endl;
    
    // 展示值
    std::cout << "\n=== 实际值 ===" << std::endl;
    std::cout << "signed char: " << static_cast<int>(s_char) << std::endl;
    std::cout << "unsigned char: " << static_cast<int>(u_char) << std::endl;
    std::cout << "signed int: " << s_int << std::endl;
    std::cout << "unsigned int: " << u_int << std::endl;
    
    return 0;
}

符号修饰符的使用场景

cpp
#include <iostream>

// 年龄只能为正数,使用unsigned
void print_age(unsigned int age) {
    std::cout << "年龄: " << age << " 岁" << std::endl;
}

// 温度可以为负数,使用signed
void print_temperature(signed int temperature) {
    std::cout << "温度: " << temperature << "°C" << std::endl;
}

// 字节操作通常使用unsigned char
void print_bytes(const unsigned char* data, size_t length) {
    std::cout << "字节数据: ";
    for (size_t i = 0; i < length; ++i) {
        std::cout << static_cast<int>(data[i]) << " ";
    }
    std::cout << std::endl;
}

int main() {
    // 合适的使用场景
    print_age(25);              // 年龄为正数
    print_temperature(-10);     // 温度可为负数
    print_temperature(30);      // 温度也可为正数
    
    // 字节操作
    unsigned char bytes[] = {0xFF, 0x00, 0xAB, 0xCD};
    print_bytes(bytes, sizeof(bytes));
    
    // 注意溢出问题
    unsigned int small_unsigned = 0;
    std::cout << "unsigned减1前: " << small_unsigned << std::endl;
    small_unsigned--;  // 下溢,变成很大的正数
    std::cout << "unsigned减1后: " << small_unsigned << std::endl;
    
    return 0;
}

📏 大小修饰符

short、long和long long

cpp
#include <iostream>
#include <climits>

int main() {
    // 基本整数类型
    short short_int = 32767;
    int normal_int = 2147483647;
    long long_int = 2147483647L;
    long long long_long_int = 9223372036854775807LL;
    
    // 可以省略int关键字
    short s = 100;
    long l = 200L;
    long long ll = 300LL;
    
    // 输出大小信息
    std::cout << "=== 类型大小 ===" << std::endl;
    std::cout << "short: " << sizeof(short) << " 字节" << std::endl;
    std::cout << "int: " << sizeof(int) << " 字节" << std::endl;
    std::cout << "long: " << sizeof(long) << " 字节" << std::endl;
    std::cout << "long long: " << sizeof(long long) << " 字节" << std::endl;
    
    // 输出范围信息
    std::cout << "\n=== 类型范围 ===" << std::endl;
    std::cout << "short: " << SHRT_MIN << " 到 " << SHRT_MAX << std::endl;
    std::cout << "int: " << INT_MIN << " 到 " << INT_MAX << std::endl;
    std::cout << "long: " << LONG_MIN << " 到 " << LONG_MAX << std::endl;
    std::cout << "long long: " << LLONG_MIN << " 到 " << LLONG_MAX << std::endl;
    
    // 组合使用
    unsigned short us = 65535;
    unsigned long ul = 4294967295UL;
    unsigned long long ull = 18446744073709551615ULL;
    
    std::cout << "\n=== 无符号类型 ===" << std::endl;
    std::cout << "unsigned short: " << us << std::endl;
    std::cout << "unsigned long: " << ul << std::endl;
    std::cout << "unsigned long long: " << ull << std::endl;
    
    return 0;
}

选择合适的整数类型

cpp
#include <iostream>
#include <cstdint>  // 固定宽度整数类型

// 不同场景下的类型选择
void demonstrate_type_selection() {
    // 1. 一般用途:使用int
    int counter = 0;
    int array_size = 100;
    
    // 2. 循环索引:使用size_t(无符号)
    std::vector<int> data = {1, 2, 3, 4, 5};
    for (size_t i = 0; i < data.size(); ++i) {
        std::cout << data[i] << " ";
    }
    std::cout << std::endl;
    
    // 3. 内存大小:使用size_t
    size_t memory_size = sizeof(data);
    std::cout << "内存大小: " << memory_size << " 字节" << std::endl;
    
    // 4. 大数值:使用long long
    long long population = 7800000000LL;  // 全球人口
    std::cout << "全球人口: " << population << std::endl;
    
    // 5. 精确宽度需求:使用固定宽度类型
    std::int32_t precise_32bit = 1000000;
    std::uint64_t precise_64bit = 1000000000000ULL;
    
    std::cout << "32位整数: " << precise_32bit << std::endl;
    std::cout << "64位无符号整数: " << precise_64bit << std::endl;
    
    // 6. 文件偏移等:使用适当的类型
    std::streamoff file_offset = 1024;
    std::cout << "文件偏移: " << file_offset << std::endl;
}

int main() {
    demonstrate_type_selection();
    return 0;
}

📍 存储类修饰符

auto、register、static、extern

cpp
#include <iostream>

// 全局变量
int global_var = 100;

// extern声明(变量定义在其他文件中)
extern int external_var;  // 假设在其他文件中定义

// 静态全局变量(仅在当前文件可见)
static int file_static_var = 200;

void demonstrate_storage_classes() {
    // 1. auto(C++11前的用法,现已改变)
    // 在C++11之前,auto表示自动存储期,但通常省略
    // 现在auto用于类型推导
    auto automatic_var = 42;  // 现代C++中的auto
    
    // 2. register(提示编译器优化)
    // 注意:C++17中register被废弃
    // register int fast_var = 10;  // 不推荐使用
    
    // 3. static局部变量(保持值在函数调用之间)
    static int call_count = 0;
    call_count++;
    std::cout << "函数调用次数: " << call_count << std::endl;
    
    // 4. 局部变量(自动存储期)
    int local_var = 300;
    std::cout << "局部变量: " << local_var << std::endl;
    
    // 访问全局变量
    std::cout << "全局变量: " << global_var << std::endl;
    std::cout << "文件静态变量: " << file_static_var << std::endl;
}

// 静态函数(仅在当前文件可见)
static void static_function() {
    std::cout << "静态函数调用" << std::endl;
}

// extern函数声明
extern void external_function();  // 定义在其他地方

int main() {
    std::cout << "=== 存储类演示 ===" << std::endl;
    
    // 多次调用以观察static变量的行为
    demonstrate_storage_classes();
    demonstrate_storage_classes();
    demonstrate_storage_classes();
    
    static_function();
    
    return 0;
}

静态成员

cpp
#include <iostream>

class Counter {
private:
    static int total_count_;    // 静态成员变量
    int instance_id_;           // 实例成员变量
    
public:
    // 构造函数
    Counter() {
        total_count_++;
        instance_id_ = total_count_;
        std::cout << "创建对象 #" << instance_id_ << std::endl;
    }
    
    // 析构函数
    ~Counter() {
        std::cout << "销毁对象 #" << instance_id_ << std::endl;
    }
    
    // 静态成员函数
    static int getTotalCount() {
        // 只能访问静态成员
        return total_count_;
        // return instance_id_;  // 错误!不能访问实例成员
    }
    
    // 实例成员函数
    int getInstanceId() const {
        return instance_id_;
    }
    
    // 静态成员函数:重置计数器
    static void resetCounter() {
        total_count_ = 0;
    }
};

// 静态成员定义(必须在类外定义)
int Counter::total_count_ = 0;

void demonstrate_static_members() {
    std::cout << "初始计数: " << Counter::getTotalCount() << std::endl;
    
    {
        Counter c1, c2, c3;
        std::cout << "当前总数: " << Counter::getTotalCount() << std::endl;
        std::cout << "c2的ID: " << c2.getInstanceId() << std::endl;
    }  // c1, c2, c3在这里被销毁
    
    std::cout << "作用域结束后总数: " << Counter::getTotalCount() << std::endl;
    
    // 重置计数器
    Counter::resetCounter();
    std::cout << "重置后计数: " << Counter::getTotalCount() << std::endl;
}

int main() {
    demonstrate_static_members();
    return 0;
}

🔧 类型限定符

const、volatile、mutable

cpp
#include <iostream>
#include <thread>
#include <chrono>

// volatile示例:硬件寄存器或多线程共享变量
volatile int hardware_register = 0;

class VolatileExample {
private:
    volatile bool running_;     // volatile成员
    mutable int access_count_;  // mutable成员
    const int id_;              // const成员
    
public:
    VolatileExample(int id) : running_(true), access_count_(0), id_(id) {}
    
    // const成员函数中修改mutable成员
    bool isRunning() const {
        access_count_++;        // 可以修改mutable成员
        return running_;        // volatile确保每次都从内存读取
    }
    
    void stop() {
        running_ = false;       // volatile确保立即写入内存
    }
    
    int getAccessCount() const {
        return access_count_;
    }
    
    int getId() const {
        return id_;             // const成员不能修改
    }
};

// 线程函数,用于演示volatile
void worker_thread(VolatileExample* obj) {
    int count = 0;
    while (obj->isRunning()) {
        count++;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        if (count > 10) {
            obj->stop();
        }
    }
    std::cout << "工作线程结束,循环了 " << count << " 次" << std::endl;
}

int main() {
    std::cout << "=== 类型限定符演示 ===" << std::endl;
    
    // const变量
    const int MAX_SIZE = 100;
    std::cout << "常量: " << MAX_SIZE << std::endl;
    
    // volatile变量(模拟硬件寄存器)
    hardware_register = 42;
    std::cout << "硬件寄存器值: " << hardware_register << std::endl;
    
    // mutable示例
    VolatileExample example(1);
    std::cout << "对象ID: " << example.getId() << std::endl;
    
    // 多次调用const函数,观察mutable成员的变化
    for (int i = 0; i < 5; ++i) {
        example.isRunning();
    }
    std::cout << "访问次数: " << example.getAccessCount() << std::endl;
    
    // 线程示例(演示volatile的作用)
    std::cout << "\n=== 多线程示例 ===" << std::endl;
    VolatileExample thread_example(2);
    
    std::thread worker(worker_thread, &thread_example);
    
    // 主线程等待
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::cout << "主线程检查状态..." << std::endl;
    
    worker.join();
    std::cout << "线程演示结束" << std::endl;
    
    return 0;
}

const的深入应用

cpp
#include <iostream>
#include <vector>
#include <memory>

class ConstCorrectness {
private:
    std::vector<int> data_;
    mutable bool cache_valid_;
    mutable int cached_sum_;
    
public:
    ConstCorrectness(std::initializer_list<int> values) 
        : data_(values), cache_valid_(false), cached_sum_(0) {}
    
    // const成员函数重载
    const int& at(size_t index) const {
        return data_.at(index);
    }
    
    int& at(size_t index) {
        cache_valid_ = false;  // 非const版本可能修改数据
        return data_.at(index);
    }
    
    // const成员函数,但内部有缓存逻辑
    int sum() const {
        if (!cache_valid_) {
            cached_sum_ = 0;
            for (const auto& value : data_) {
                cached_sum_ += value;
            }
            cache_valid_ = true;
            std::cout << "计算并缓存求和结果" << std::endl;
        } else {
            std::cout << "使用缓存的求和结果" << std::endl;
        }
        return cached_sum_;
    }
    
    void add(int value) {
        data_.push_back(value);
        cache_valid_ = false;
    }
    
    size_t size() const {
        return data_.size();
    }
};

// 函数重载:const和非const版本
void process_data(ConstCorrectness& data) {
    std::cout << "处理非const数据" << std::endl;
    data.add(100);  // 可以修改
}

void process_data(const ConstCorrectness& data) {
    std::cout << "处理const数据" << std::endl;
    std::cout << "大小: " << data.size() << std::endl;
    std::cout << "求和: " << data.sum() << std::endl;
}

int main() {
    std::cout << "=== const正确性演示 ===" << std::endl;
    
    ConstCorrectness data{1, 2, 3, 4, 5};
    
    // 非const对象
    std::cout << "\n--- 非const对象 ---" << std::endl;
    process_data(data);
    std::cout << "修改后求和: " << data.sum() << std::endl;
    
    // const对象
    std::cout << "\n--- const对象 ---" << std::endl;
    const ConstCorrectness const_data{10, 20, 30};
    process_data(const_data);
    
    // 再次调用sum(),观察缓存效果
    std::cout << "再次求和: " << const_data.sum() << std::endl;
    
    // 指针和const
    std::cout << "\n--- 指针和const ---" << std::endl;
    const ConstCorrectness* ptr_to_const = &data;
    // ptr_to_const->add(200);  // 错误!不能通过const指针修改
    std::cout << "通过const指针访问: " << ptr_to_const->size() << std::endl;
    
    return 0;
}

🎯 修饰符组合

修饰符的组合使用

cpp
#include <iostream>

// 各种修饰符的组合
class ModifierCombinations {
private:
    // 基本组合
    static const int STATIC_CONST = 100;
    static const unsigned long STATIC_CONST_ULONG = 1000000UL;
    
    // 复杂组合
    mutable volatile unsigned short status_;
    const volatile int* hardware_ptr_;
    
public:
    ModifierCombinations() 
        : status_(0), hardware_ptr_(nullptr) {}
    
    // 各种函数修饰符组合
    static const unsigned int getStaticConstValue() {
        return STATIC_CONST;
    }
    
    const volatile unsigned short getStatus() const {
        return status_;
    }
    
    void updateStatus(unsigned short new_status) {
        status_ = new_status;
    }
};

// 函数参数的修饰符组合
void complex_function(
    const unsigned long long* const ptr,  // 指向const unsigned long long的const指针
    volatile unsigned char& ref,           // volatile unsigned char的引用
    const volatile short value            // const volatile short值
) {
    std::cout << "复杂函数参数处理" << std::endl;
    std::cout << "指针指向的值: " << *ptr << std::endl;
    std::cout << "引用的值: " << static_cast<int>(ref) << std::endl;
    std::cout << "值参数: " << value << std::endl;
}

int main() {
    std::cout << "=== 修饰符组合演示 ===" << std::endl;
    
    ModifierCombinations obj;
    
    // 访问静态const成员
    std::cout << "静态常量值: " << obj.getStaticConstValue() << std::endl;
    
    // 状态操作
    obj.updateStatus(42);
    std::cout << "状态值: " << obj.getStatus() << std::endl;
    
    // 复杂函数调用
    const unsigned long long big_value = 9876543210ULL;
    volatile unsigned char byte_value = 255;
    const volatile short short_value = -1000;
    
    complex_function(&big_value, byte_value, short_value);
    
    // 展示各种类型的大小
    std::cout << "\n=== 类型大小信息 ===" << std::endl;
    std::cout << "unsigned short: " << sizeof(unsigned short) << " 字节" << std::endl;
    std::cout << "const long: " << sizeof(const long) << " 字节" << std::endl;
    std::cout << "volatile int: " << sizeof(volatile int) << " 字节" << std::endl;
    std::cout << "unsigned long long: " << sizeof(unsigned long long) << " 字节" << std::endl;
    
    return 0;
}

现代C++中的修饰符

cpp
#include <iostream>
#include <type_traits>

// C++11及以后的修饰符
class ModernModifiers {
private:
    // constexpr成员
    static constexpr int COMPILE_TIME_CONST = 42;
    static constexpr double PI = 3.14159;
    
    // auto成员(需要初始化)
    // C++17: 可以在类内使用auto
    static inline auto class_name = "ModernModifiers";
    
public:
    // constexpr构造函数
    constexpr ModernModifiers() = default;
    
    // constexpr成员函数
    constexpr int getConstValue() const {
        return COMPILE_TIME_CONST;
    }
    
    // C++14: constexpr可以包含更复杂的逻辑
    constexpr int fibonacci(int n) const {
        if (n <= 1) return n;
        return fibonacci(n-1) + fibonacci(n-2);
    }
    
    // C++17: constexpr if
    template<typename T>
    constexpr auto process(T value) const {
        if constexpr (std::is_integral_v<T>) {
            return value * 2;
        } else {
            return value + 1.0;
        }
    }
};

// C++20: consteval(强制编译时求值)
#if __cpp_consteval >= 201811L
consteval int compile_time_only(int x) {
    return x * x;  // 必须在编译时计算
}
#endif

int main() {
    std::cout << "=== 现代C++修饰符 ===" << std::endl;
    
    constexpr ModernModifiers obj;
    
    // 编译时计算
    constexpr int const_value = obj.getConstValue();
    constexpr int fib_10 = obj.fibonacci(10);
    
    std::cout << "编译时常量: " << const_value << std::endl;
    std::cout << "第10个斐波那契数: " << fib_10 << std::endl;
    
    // constexpr if示例
    constexpr auto int_result = obj.process(42);
    constexpr auto double_result = obj.process(3.14);
    
    std::cout << "整数处理结果: " << int_result << std::endl;
    std::cout << "浮点处理结果: " << double_result << std::endl;
    
    // C++20 consteval
    #if __cpp_consteval >= 201811L
    constexpr auto square_5 = compile_time_only(5);
    std::cout << "编译时平方: " << square_5 << std::endl;
    #endif
    
    // 类型特征检查
    std::cout << "\n=== 类型特征 ===" << std::endl;
    std::cout << "const int 是const: " << std::is_const_v<const int> << std::endl;
    std::cout << "volatile int 是volatile: " << std::is_volatile_v<volatile int> << std::endl;
    std::cout << "unsigned int 是无符号: " << std::is_unsigned_v<unsigned int> << std::endl;
    
    return 0;
}

总结

C++修饰符类型提供了丰富的方式来精确控制数据的特性:

修饰符分类

  • 符号修饰符:signed/unsigned - 控制数值的符号性
  • 大小修饰符:short/long/long long - 控制数据大小
  • 存储类修饰符:static/extern/auto - 控制存储和链接
  • 类型限定符:const/volatile/mutable - 控制访问和优化

使用原则

  • 选择合适的符号性:根据数据范围选择signed或unsigned
  • 考虑性能和内存:根据需要选择合适的大小修饰符
  • 正确使用const:提高代码安全性和可读性
  • 谨慎使用volatile:主要用于硬件访问和多线程编程

现代C++改进

  • constexpr提供编译时计算能力
  • auto简化类型声明
  • 更强的类型安全检查
  • 更好的优化支持

正确使用修饰符可以:

  • 提高代码的正确性和安全性
  • 优化内存使用和性能
  • 增强代码的可读性和维护性
  • 支持编译器进行更好的优化

本站内容仅供学习和研究使用。