【字符编码】constexpr、char[]赋值汉字

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


c 复制代码
最后两个问题
1、关于constexpr
你上面提到了并非基础类型支持constexpr,自定义类型构造函数支持constexpr,这种类型就支持constexpr,
以及char支持,char*也支持,那么上面的point结构体构造函数支持constexpr,那么point支持,point*类型也就支持是吗,
之前你提到过std::string不支持constexpr,那么std::string*是不是也不支持,
一种数据类型支持,这种数据类型指针类型就支持,
反之,这种数据类型不支持,这种数据类型对应的指针类型也不支持是吗

2、关于字符数组赋值汉字
char arr[]="哈哈"赋值之后可以正确使用
char arr[] = {'哈','哈','\0'}这种就乱码,是不是字符数组赋值汉字只能用char arr[]="哈哈"形式,还有其他手段吗

你现在想确认两个核心问题:一是constexpr与指针类型的关系(某类型支持constexpr则其指针也支持?反之则不支持?),包括point*std::string*的具体情况;二是字符数组用{}赋值汉字乱码的原因,以及除了字符串形式外是否有其他赋值手段。我会逐一拆解,纠正核心误区。


问题1:constexpr与指针类型的关系(核心纠正误区)

你的核心误区是:认为"某类型支持constexpr ↔ 该类型的指针也支持constexpr"------这个结论是错误的

constexpr对指针类型的支持,核心看两个维度,和"指向的类型本身是否支持constexpr"无直接绑定关系:

  1. 指针类型本身能否被constexpr修饰 :所有指针类型(不管指向什么)都可以被constexpr修饰;
  2. 指针的初始化值是否是"编译期常量地址":这是能否编译通过的关键,和指向的类型无关。

1.1 先明确:constexpr指针的本质

constexpr修饰指针时,要求的是指针存储的地址值是编译期可确定的常量 ,而非"指向的对象是constexpr对象"(后者只是获取编译期地址的常见方式)。

1.2 分场景验证(结合你的例子)

场景1:Point* 能否用constexpr
  • 情况1:初始化地址是编译期常量 → 合法
cpp 复制代码
struct Point {
    constexpr Point(int x_, int y_) : x(x_), y(y_) {}
    int x, y;
};

// 1. p是constexpr对象,地址&p是编译期常量 → Point*支持constexpr
constexpr Point p(10, 20); 
constexpr Point* pp = &p;  // 合法!pp是constexpr指针

// 2. nullptr是编译期常量 → 即使指向非constexpr类型,也合法
constexpr Point* pp2 = nullptr; // 合法!
  • 情况2:初始化地址是运行期变量 → 非法
cpp 复制代码
Point p2(30, 40); // p2是运行期对象,地址&p2是运行期确定
constexpr Point* pp3 = &p2; // 非法!编译报错(地址不是编译期常量)
场景2:std::string* 能否用constexpr

首先明确:std::string(C++17及之前)的构造函数不是constexpr,所以无法创建constexprstd::string对象,但**std::string*指针本身可以被constexpr修饰**,只要初始化地址是编译期常量:

cpp 复制代码
// 情况1:初始化地址是nullptr(编译期常量)→ 合法
constexpr std::string* ps1 = nullptr; // 合法!

// 情况2:初始化地址是运行期std::string对象 → 非法
std::string s = "hello";
constexpr std::string* ps2 = &s; // 非法!编译报错(地址是运行期的)

// 补充:C++20开始,std::string支持constexpr,但核心逻辑不变
#if __cpp_lib_constexpr_string >= 201907L
constexpr std::string s_const = "hello"; // C++20+合法
constexpr std::string* ps3 = &s_const;  // 合法!地址是编译期常量
#endif

1.3 总结你的核心问题

  • ❌ 错误认知:"类型支持constexpr → 其指针也支持;类型不支持 → 指针也不支持"
  • ✅ 正确逻辑:
    1. 任何指针类型都可以被constexpr修饰(语法上支持);
    2. 能否编译通过,只看指针的初始化地址是否是编译期常量 (如constexpr对象的地址、nullptr、字符串字面量地址);
    3. 指向的类型是否支持constexpr,只是"能否获取编译期地址"的条件之一,而非指针本身能否用constexpr的条件。

问题2:字符数组赋值汉字的问题

2.1 为什么char arr[] = {'哈','哈','\0'}会乱码?

核心原因:单字符字面量'哈'在编译时会被编译器截断为1字节,丢失了汉字的多字节编码信息,导致数组中存储的是无效字节,自然乱码。

拆解过程(以UTF-8编码为例):

  1. "哈"的UTF-8完整编码是3字节:0xE5 0x93 0x88
  2. 当你写'哈'时,编译器无法把3字节塞进1个char,会截断 (通常取最后1字节),变成0x88
  3. 所以char arr[] = {'哈','哈','\0'}实际存储的是:0x88, 0x88, 0x00 → 这不是"哈"的有效编码,输出自然乱码。

2.2 字符数组赋值汉字的正确手段(不止字符串形式)

字符串形式char arr[] = "哈哈"是最简洁的,但也有其他合法手段,核心是手动写入汉字的完整多字节编码(十六进制) ,而非直接写'哈'

手段1:手动写入多字节编码({}形式,推荐)
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    // 方式1:UTF-8编码("哈"=0xE5 0x93 0x88)
    char arr1[] = {0xE5, 0x93, 0x88, 0xE5, 0x93, 0x88, 0x00}; 
    // 方式2:GBK编码("哈"=0xB9 0xFE)
    char arr2[] = {0xB9, 0xFE, 0xB9, 0xFE, 0x00}; 

    // 验证输出(需确保控制台编码匹配,比如UTF-8)
    cout << arr1 << endl; // 输出:哈哈
    // arr2需控制台设为GBK才会正常输出,UTF-8下会乱码
    return 0;
}
手段2:运行期手动赋值字节
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    char arr3[10] = {0}; // 初始化全0
    // 手动赋值UTF-8的"哈"
    arr3[0] = 0xE5;
    arr3[1] = 0x93;
    arr3[2] = 0x88;
    arr3[3] = 0xE5;
    arr3[4] = 0x93;
    arr3[5] = 0x88;
    arr3[6] = 0x00;
    cout << arr3 << endl; // 输出:哈哈
    return 0;
}
手段3:使用宽字符/Unicode(更规范的多字符处理)

如果需要更通用的汉字处理,推荐用宽字符类型(wchar_t)或C++11的UTF-8字符串:

cpp 复制代码
#include <iostream>
#include <locale> // 用于设置本地化
using namespace std;

int main() {
    // 方式1:宽字符(wchar_t)
    wchar_t w_arr[] = L"哈哈"; // L前缀表示宽字符字面量
    wcout.imbue(locale(""));  // 设置本地化,否则宽字符输出乱码
    wcout << w_arr << endl;   // 输出:哈哈

    // 方式2:C++11 UTF-8字符串(推荐现代C++)
    const char* u8_arr = u8"哈哈"; // u8前缀表示UTF-8字面量
    cout << u8_arr << endl;       // 输出:哈哈
    return 0;
}

2.3 关键注意事项

  • 所有手段的核心:汉字是多字节,必须保证字节数完整,且编码格式(UTF-8/GBK)和控制台/文件编码一致
  • 字符串形式"哈哈"的优势:编译器自动解析编码并填充完整字节,无需手动写十六进制,是最省心的方式。

总结

  1. constexpr与指针的核心逻辑:任何指针类型都可被constexpr修饰,能否编译通过仅看指针初始化地址是否为编译期常量,与指向的类型是否支持constexpr无直接绑定;
  2. 字符数组赋值汉字的关键:不能直接用'哈'(会截断),除了字符串形式,还可手动写入汉字的完整多字节编码(十六进制),或使用宽字符/UTF-8字面量。
相关推荐
在路上看风景7 小时前
19. 成员初始化列表和初始化对象
c++
zmzb01037 小时前
C++课后习题训练记录Day98
开发语言·c++
念风零壹7 小时前
C++ 内存避坑指南:如何用移动语义和智能指针解决“深拷贝”与“内存泄漏”
c++
孞㐑¥8 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
MZ_ZXD00110 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
A星空12311 小时前
一、Linux嵌入式的I2C驱动开发
linux·c++·驱动开发·i2c
凡人叶枫11 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
会叫的恐龙11 小时前
C++ 核心知识点汇总(第六日)(字符串)
c++·算法·字符串
小糯米60112 小时前
C++顺序表和vector
开发语言·c++·算法
独望漫天星辰12 小时前
C++ 多态深度解析:从语法规则到底层实现(附实战验证代码)
开发语言·c++