C++进阶知识4.0

@bit::Shadow
✧(≖ ◡ ≖✿

目录

restrict修饰指针类型

[1. 什么是"别名(Alias)"问题?](#1. 什么是“别名(Alias)”问题?)

[2. restrict 如何解决这个问题?](#2. restrict 如何解决这个问题?)

[enum class强类型枚举C++11](#enum class强类型枚举C++11)

原枚举体可能出现的问题(具体由环境决定)

1.命名空间污染

2.隐式转换为整数

[enum class 的解决方案](#enum class 的解决方案)

std::function<返回类型(参数列表)>

std::function含义

private函数无法被当做参数

[uint32_t 及 u_int32_t](#uint32_t 及 u_int32_t)

string转换为char*、char*转换为string

关于void**


restrict修饰指针类型

是C99引入的关键字表示这个指针是访问其指向数据的唯一方式。

1. 什么是"别名(Alias)"问题?

看一个简单的例子,假设有两个指针 ab

复制代码
void func(int *a, int *b) {
    *a = 10;
    *b = 20;
    *a = *a + 5;  // 这里的 *a 需要重新从内存读取吗?
}
  • 编译器不知道 ab 是否指向同一块内存

  • 如果 a == b(即指向同一个地址),那么 *b = 20 会改变 *a 的值。

  • 所以编译器必须保守地 认为 ab 可能重叠,每次使用 *a 时都要重新从内存读取,而不能直接用寄存器里缓存的旧值。

这种"保守"策略会++阻止编译器进行优化++。

2. restrict 如何解决这个问题?

c

复制代码
void func(int *restrict a, int *restrict b) {
    *a = 10;
    *b = 20;
    *a = *a + 5;  // 编译器知道 a 和 b 不重叠,所以可以直接用寄存器里的 10
}
  • 程序员通过 restrict 向编译器做出承诺ab ++不会指向同一块内存++。

  • 编译器收到这个承诺后,可以放心地优化:

    • 在执行 *b = 20 后,它知道 *a 没有被修改,所以可以直接用寄存器里的值(10)来计算 *a + 5无需重新从内存读取

enum class强类型枚举C++11

原枚举体可能出现的问题(具体由环境决定)

1.命名空间污染

cpp 复制代码
enum LogLevel
{
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL
};

枚举体内定义的名字会转为"全局变量"。

2.隐式转换为整数

cpp 复制代码
// ❌ 传统 enum
enum LogLevel {
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

enum Fruit {
    APPLE,  // 冲突!APPLE 已经存在!!!
    BANANA,
    ORANGE
};

void func(LogLevel level) {}

int main() {
    func(10);           // ❌ 可以传入任意整数!
    int x = WARNING;    // ❌ 隐式转换为 int
    x = x + 5;          // ❌ 可以参与算术运算
    
    if (INFO == 1) {    // ❌ 可以与整数比较
        // ...
    }
    return 0;
}

enum class 的解决方案

cpp 复制代码
enum class LogLevel {
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
}; 

void test(){
    LogLevel lgLvel=LogLevel::DEBUG; // ✅ 必须加作用域
}

std::function<返回类型(参数列表)>

定义函数/函数对象

例如:

cpp 复制代码
#include<functional>
using func_t = std::function<void()>;

std::function<void()>含义

void:返回类型为void。

():无参数。

含义:可以存储任何无参数、无返回值的函数/函数对象。

cpp 复制代码
#include <functional>
#include <iostream>

// 普通函数
void hello() {
    std::cout << "Hello, World!" << std::endl;
}

int main() {
    std::function<void()> func = hello;  // 存储普通函数
    func();  // 调用:Hello, World!
    return 0;
}

private函数无法被当做参数

uint32_t 及 u_int32_t

是一种类型别名,保证在任何平台下均为"32位无符号整数"(4字节)。保证了兼容性。再有:int8_t、uint64_t等扩展性C/C++类型,均是为了兼容平台。(正规C/C++标准)

注意:无ulong64_t。

除此之外还有u_int32_t 等相似形式,这是BSD系统标准,兼容性较差。对比如下

方面 u_int32_t uint32_t
来源 BSD 系统(Unix 传统) C99/C++11 标准
头文件 <sys/types.h> <stdint.h>(C) <cstdint>(C++)
标准化 非标准(BSD 扩展) ✅ 标准(ISO C/C++)
可移植性 主要 BSD/Linux 系统 ✅ 所有支持 C99/C++11 的平台
命名风格 u_ 前缀(BSD 风格) _t 后缀(标准风格)
定义方式 typedef unsigned int u_int32_t; typedef unsigned int uint32_t;

string转换为char*、char*转换为string

cpp 复制代码
char* name = _name.c_str();

char*转换为string可以隐式转换少用库函数实现。

关于void**

cpp 复制代码
int main()
{
    // printf("%d\n",ThreadModule::number);
    //void**对地址的作用
    // void a = 10;//wrong!!
    int a = 10;
    int* pa = &a;
    printf("%p\n", pa);
    printf("%p\n", (void*)pa);
    // cout <<*(void*)pa);wrong 无法打印"空类型"
    // printf("%p\n", **(void**)pa);
    printf("%p\n", (void**)pa);//double转换为int可能值改变。此处不变是因为解析方式不变。
    printf("%p\n", *(void**)pa);
    return 0;
}

感谢支持,长期连载

欢迎关注