flos chen头像
关注
【C/C++ 宽窄字符详解:char、wchar_t 的原理、编码关系与跨平台互转】封面图

【C/C++ 宽窄字符详解:char、wchar_t 的原理、编码关系与跨平台互转】

avatar

🔥 个人主页: flos chen

❄️ 个人专栏: 《系统分析师》     《C/C++》

《Qt》     《Linux》     《SQL》

《深度学习》

🌟 边学习,边记录,一起学习进步!

divider

在这里插入图片描述

一、引言:一段代码,三种结局

先看一段几乎每个 C++ 初学者都写过的代码:

#include <iostream>

int main() {
    std::cout << "你好,世界" << std::endl;
    return 0;
}

在 Linux 上它可能正常输出;在 Windows 的某些环境下可能变成一串乱码;换一个编译器选项,结果又变了。为什么一个"Hello World"级别的程序,在不同平台表现如此不同?

答案就藏在本文的主题里:字符的"宽"与"窄",以及字符串在内存中到底以什么编码存在。很多 C++ 程序员用过 wchar_t、std::wstring,却说不清它们和 char、std::string 的本质区别,于是遇到乱码只能靠"试"。本文从编码原理出发,把 C++ 宽窄字符的关系讲透,并给出跨平台的现代最佳实践。

二、前置知识:字符、码点与编码单元

要理解宽窄字符,必须先理解三个概念:字符(Character)、码点(Code Point)、编码单元(Code Unit)。

2.1 ASCII 时代的错觉:字符 = 字节

ASCII 用 7 个比特给 128 个符号编号(0x00~0x7F),一个字节就能装下,所以早期程序员形成了"一个字符就是一个字节"的印象。这个印象至今仍然坑人——因为 ASCII 只覆盖英文、数字和少量符号,它从来不是为中文设计的。

2.2 多字节字符集:GBK 的"窄"字符困境

为了容纳汉字,简体中文世界出现了 GB2312/GBK 这类多字节字符集(MBCS):ASCII 字符占 1 字节(0x00~0x7F),汉字占 2 字节。注意,这里出现了第一个关键事实:

窄字符串里,一个"字符"可能占用多个字节,且具体字节数取决于编码。

GBK 的致命问题是:编码不统一。同一个 "中",在 GBK 里是 D6 D0,在 Big5(繁体)里是 A4 A4,在 UTF-8 里是 E4 B8 AD。多字节字符集之间没有统一的映射,A 系统写出的文件到 B 系统就乱码——这就是"乱码"最古老、也最广泛的来源。

2.3 Unicode:给每个字符一个唯一的编号

Unicode 试图终结这种混乱:它给全世界几乎每一个字符分配一个唯一的整数编号,称为码点(Code Point),记作 U+XXXX。比如:

字符码点
AU+0041
中U+4E2D
😀(emoji)U+1F600

Unicode 码点范围是 U+0000 ~ U+10FFFF,一共约 110 万个位置。

码点只是"编号",不是"存储形式"。同一个码点可以用不同编码规则变成字节序列,这就引出了 UTF 家族。

2.4 三种主流编码:UTF-8 / UTF-16 / UTF-32

编码变长?每字符字节数兼容 ASCII典型用途
UTF-8是1~4是(U+0000~U+007F 与 ASCII 完全一致)文件、网络、跨平台数据交换
UTF-16是(2/4 字节)2~4否Windows 系统内部、Java/.NET 字符串
UTF-32否4否需要按码点随机索引的场景
  • UTF-8:按码点大小用 1~4 字节编码,ASCII 兼容,因此对英文文本"零开销",是互联网事实标准。
  • UTF-16:U+0000~U+FFFF 用 2 字节;超出部分(如 emoji)需要用一对**代理对(Surrogate Pair)**占 4 字节。Windows 系统内部使用 UTF-16(小端序)。
  • UTF-32:每个码点固定 4 字节,索引简单但空间浪费严重(英文文本膨胀 4 倍)。

2.5 编码单元(Code Unit):宽窄的本质

编码单元是一次读写的最小单位。UTF-8 的编码单元是 1 字节,UTF-16 是 2 字节(16 位),UTF-32 是 4 字节(32 位)。一个字符可能由多个编码单元组成:

字符UTF-8 编码单元数UTF-16 编码单元数
A11
中31
😀42(代理对)

现在可以说出本文最核心的一句话了:

"宽字符"和"窄字符"的区别,本质是编码单元宽度的区别,而不是"能不能存中文"的区别。

wchar_t 之所以叫"宽",是因为它的编码单元比 char 宽(16 或 32 位);char 之所以叫"窄",是因为它的编码单元只有 8 位。两者都能存中文,但存储形式和语义完全不同。

三、C++ 的字符类型家族

C++ 的字符类型从 C++98 到 C++20 经历了三次扩展,理解这个演进脉络,就理解了宽窄字符的全部历史。

3.1 char:一字节的"字节"类型

char c = 'A';        // OK,ASCII 没问题
char c2 = '中';      // 危险:'中' 需要多个字节,char 装不下(多数编译器直接报错/截断)

char 的语义在标准里非常"暧昧":它既是"字符",又是"字节"。sizeof(char) == 1 恒定,但 1 个 char 不保证能表示一个字符。一个 std::string 存中文时,size() 返回的是字节数,不是字符数:

#include <iostream>
#include <string>

int main() {
    const std::string s = "中";        // 假设源码和执行字符集都是 UTF-8
    std::cout << "字节数: " << s.size() << '\n';      // 输出 3,而不是 1
    for (unsigned char c : s) {                       // e4 b8 ad
        std::cout << std::hex << static_cast<int>(c) << ' ';
    }
    std::cout << '\n';
}

3.2 wchar_t:宽度由平台决定的"宽字符"

wchar_t 是 C++98 就有的宽字符类型,但它的大小和编码都是实现定义的——这是它最大的问题:

平台sizeof(wchar_t)实际编码
Windows(MSVC)2 字节UTF-16(小端)
Linux / macOS(GCC/Clang)4 字节UTF-32
#include <iostream>

int main() {
    // Windows 输出 2,Linux/macOS 输出 4
    std::cout << "sizeof(wchar_t) = " << sizeof(wchar_t) << '\n';
}

这意味着:用 std::wstring 写的代码,在 Windows 上是 UTF-16 语义,在 Linux 上却是 UTF-32 语义。同一个 L"中",在 Windows 里占 1 个编码单元(2 字节),在 Linux 里占 1 个编码单元(4 字节),而一个 emoji 在 Windows 里占 2 个编码单元、在 Linux 里占 1 个。跨平台代码一旦涉及宽字符,行为立刻分叉——这就是 wchar_t 被称为"不可移植陷阱"的原因。

3.3 char16_t 与 char32_t(C++11):把编码写进类型

C++11 意识到 wchar_t 的混乱,引入了两个编码固定的类型:

char16_t a = u'中';    // 固定 16 位,UTF-16 编码单元
char32_t b = U'中';    // 固定 32 位,UTF-32 编码单元(一个码点)

char16_t 和 char32_t 与平台无关:无论在 Windows 还是 Linux,sizeof(char16_t) == 2、sizeof(char32_t) == 4 恒成立。可惜它们只在 C++11 之后可用,且 API 生态(尤其是 Windows)并不买账。

3.4 char8_t(C++20):为 UTF-8 正名

C++20 之前,u8"..." 字面量的类型是 const char[],和普通窄字符串无法区分——这带来两个问题:

  1. 重载歧义:void f(const char*); void f(const wchar_t*); 调用 f(u8"x") 会走窄字符串重载,但调用者本意是"UTF-8 数据",语义被稀释。
  2. 类型不安全:UTF-8 字符串可以被静默地和 GBK 窄字符串拼接,编码混用而编译器毫无察觉。

C++20 引入 char8_t(P0482 提案)彻底解决:

char8_t c = u8'中';          // C++20:类型为 char8_t
std::u8string s = u8"中文";  // C++20:std::basic_string<char8_t>

char8_t 仍然是 1 字节,但类型上明确表达"这是 UTF-8 编码单元",与普通 char 不再能隐式互转,从编译期就拦截编码混用。GCC 10+、Clang 7+、MSVC 2019 16.10+ 在 C++20 模式下均支持。

3.5 字符类型汇总表

类型sizeof(常见平台)编码引入版本对应字符串类型备注
char1实现定义(执行字符集)C++98std::string本质是"字节",不保证是字符
wchar_tWindows: 2 / Linux: 4平台相关C++98std::wstring可移植性最差
char16_t2UTF-16C++11std::u16string编码固定
char32_t4UTF-32C++11std::u32string每个码点一个单元
char8_t1UTF-8 编码单元C++20std::u8string类型上明确"这是 UTF-8"

四、字符串字面量与"执行字符集"

4.1 字面量前缀对照表

const char*     s1 = "中文";        // 编码 = 执行字符集(不确定!)
const wchar_t*  s2 = L"中文";       // 编码 = 宽执行字符集(平台相关)
const char16_t* s3 = u"中文";       // UTF-16,固定
const char32_t* s4 = U"中文";       // UTF-32,固定
const char8_t*  s5 = u8"中文";      // C++20 起类型为 const char8_t*,UTF-8 固定
前缀字面量类型(C++20 起)编码
"..."const char[]执行字符集(实现定义)
L"..."const wchar_t[]宽执行字符集(平台相关)
u8"..."const char8_t[]UTF-8
u"..."const char16_t[]UTF-16
U"..."const char32_t[]UTF-32

注意:u8、u、U 前缀的编码是标准强制固定的,不受平台和编译器选项影响;而裸 "..." 和 L"..." 的编码是实现定义的——这正是乱码的温床。

4.2 源字符集与执行字符集:乱码的第一来源

C++ 标准区分两个概念:

  • 源字符集(Source Charset):.cpp 源文件本身的编码(你保存文件时选的编码)。
  • 执行字符集(Execution Charset):字符串字面量在运行时内存中的编码(编译后存进二进制里的字节)。

一个 "中" 字面量要正确,必须经过:源文件编码 →(编译器转换)→ 执行字符集。任何一步不匹配,字节就错了:

源文件(UTF-8) ──编译器──► 执行字符集(UTF-8) ──运行时──► 终端(UTF-8)   ✅ 正常
源文件(GBK)   ──编译器──► 执行字符集(UTF-8) ──运行时──► 终端(UTF-8)   ❌ 乱码
源文件(UTF-8) ──编译器──► 执行字符集(GBK)  ──运行时──► 终端(GBK)     ❌ 乱码

编译器相关选项:

# GCC/Clang
g++ -finput-charset=UTF-8 -fexec-charset=UTF-8 main.cpp   # 默认多为 UTF-8
# MSVC(VS2015 15.3 起)
cl /utf-8 main.cpp        # 等价于 /source-charset:utf-8 /execution-charset:utf-8

这里有一个高频坑:MSVC 默认使用系统本地代码页(中文 Windows 为 GBK/936)作为源和执行字符集。如果你的源码保存为无 BOM 的 UTF-8,又没加 /utf-8,编译器会把 UTF-8 字节当作 GBK 处理,中文立即乱码。Windows 上用 MSVC 编译含中文的源码,务必加 /utf-8 或让文件带 BOM。

五、宽窄字符的转换:原理与实现

5.1 关系本质

宽窄字符串的转换,本质是编码转换:把"字节序列 + 编码 A"翻译成"编码单元序列 + 编码 B"。转换前必须知道两侧编码,否则就是瞎猜。

5.2 C 库函数 mbstowcs / wcstombs(依赖 locale)

C 标准库提供 mbstowcs / wcstombs,但它们依赖进程 locale,不指定具体编码,可移植性很差:

#include <clocale>
#include <cstdlib>
#include <iostream>
#include <string>

int main() {
    setlocale(LC_ALL, "");            // 切换到系统 locale(Linux 下通常是 UTF-8)
    const char* narrow = "中文";
    std::wstring wide(64, L'\0');
    const std::size_t n = mbstowcs(&wide[0], narrow, wide.size());
    if (n == static_cast<std::size_t>(-1)) {
        std::cerr << "转换失败:当前 locale 无法解码该字节序列\n";
        return 1;
    }
    wide.resize(n);
    std::wcout << wide << L'\n';
}

致命缺点:转换结果取决于 setlocale 设置的 locale。Linux 终端是 UTF-8 locale 就按 UTF-8 转,Windows 控制台是 GBK 代码页就按 GBK 转——同样的代码,两边转出的字节不同,程序一跨平台就行为漂移。

5.3 std::wstring_convert:方便,但已被弃用

C++11 提供了 std::wstring_convert 配合 std::codecvt_utf8 等 facet:

#include <locale>
#include <string>

std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
std::string  utf8 = conv.to_bytes(L"中文");    // 宽 -> UTF-8
std::wstring wide = conv.from_bytes(utf8);     // UTF-8 -> 宽

问题在于:它的错误处理依赖 std::range_error 异常,设计糟糕;且与 locale 纠缠不清。C++17 起标准委员会已将其标记为弃用(deprecated),并明确不推荐新代码使用。社区普遍认为:与其用这个半吊子 API,不如自己写转换或使用第三方库。

5.4 Windows 平台:MultiByteToWideChar / WideCharToMultiByte

Windows 上 wchar_t 就是 UTF-16,Win32 API 提供了高效且不依赖 locale 的转换函数:

#include <windows.h>
#include <string>

// UTF-8 窄字符串 -> UTF-16 宽字符串
std::wstring Utf8ToWide(const std::string& utf8) {
    if (utf8.empty()) return {};
    const int len = MultiByteToWideChar(CP_UTF8, 0,
        utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
    std::wstring w(len, L'\0');
    MultiByteToWideChar(CP_UTF8, 0,
        utf8.data(), static_cast<int>(utf8.size()), w.data(), len);
    return w;
}

// UTF-16 宽字符串 -> UTF-8 窄字符串
std::string WideToUtf8(const std::wstring& w) {
    if (w.empty()) return {};
    const int len = WideCharToMultiByte(CP_UTF8, 0,
        w.data(), static_cast<int>(w.size()), nullptr, 0, nullptr, nullptr);
    std::string s(len, '\0');
    WideCharToMultiByte(CP_UTF8, 0,
        w.data(), static_cast<int>(w.size()), s.data(), len, nullptr, nullptr);
    return s;
}

注意:CP_UTF8 是写死的,转换结果与系统 locale 无关,这才是跨平台程序在 Windows 侧该用的姿势。

5.5 手写 UTF-8 ↔ UTF-16 转换(理解原理的关键)

不依赖任何平台 API,理解编解码算法后,可以自己写出正确的转换。这段代码同时展示了 UTF-8 变长解码和 UTF-16 代理对机制,是理解宽窄字符最好的教材:

#include <cstdint>
#include <stdexcept>
#include <string>
#include <vector>

// ---- UTF-8 解码:从位置 i 解出一个码点,i 前进到该码点末尾 ----
std::int32_t decode_utf8(const std::string& s, std::size_t& i) {
    const auto b0 = static_cast<unsigned char>(s[i]);
    if (b0 < 0x80) { i += 1; return b0; }              // 1 字节:ASCII

    std::uint32_t cp = 0;
    int trailing = 0;                                  // 续字节个数
    if      ((b0 & 0xE0) == 0xC0) { cp = b0 & 0x1F; trailing = 1; }
    else if ((b0 & 0xF0) == 0xE0) { cp = b0 & 0x0F; trailing = 2; }
    else if ((b0 & 0xF8) == 0xF0) { cp = b0 & 0x07; trailing = 3; }
    else return -1;                                    // 非法首字节

    if (i + trailing >= s.size()) return -1;           // 越界
    for (int k = 1; k <= trailing; ++k) {
        const auto b = static_cast<unsigned char>(s[i + k]);
        if ((b & 0xC0) != 0x80) return -1;             // 续字节必须以 10 开头
        cp = (cp << 6) | (b & 0x3F);
    }
    // 拒绝过长编码与代理区(UTF-8 规范禁止编码代理对)
    if ((trailing == 1 && cp < 0x80) ||
        (trailing == 2 && cp < 0x800) ||
        (trailing == 3 && cp < 0x10000) ||
        (cp >= 0xD800 && cp <= 0xDFFF) || cp > 0x10FFFF) {
        return -1;
    }
    i += trailing + 1;
    return static_cast<std::int32_t>(cp);
}

// ---- 码点 -> UTF-16:超出 BMP 时生成代理对 ----
void append_utf16(std::uint32_t cp, std::vector<std::uint16_t>& out) {
    if (cp < 0x10000) {
        out.push_back(static_cast<std::uint16_t>(cp));
    } else {
        cp -= 0x10000;
        out.push_back(static_cast<std::uint16_t>(0xD800 | (cp >> 10)));   // 高代理
        out.push_back(static_cast<std::uint16_t>(0xDC00 | (cp & 0x3FF))); // 低代理
    }
}

// ---- UTF-8 -> UTF-16 ----
std::vector<std::uint16_t> utf8_to_utf16(const std::string& s) {
    std::vector<std::uint16_t> out;
    std::size_t i = 0;
    while (i < s.size()) {
        const auto cp = decode_utf8(s, i);
        if (cp < 0) throw std::runtime_error("非法 UTF-8 序列");
        append_utf16(static_cast<std::uint32_t>(cp), out);
    }
    return out;
}

// ---- UTF-16 解码:处理代理对 ----
std::int32_t decode_utf16(const std::vector<std::uint16_t>& s, std::size_t& i) {
    const auto u = s[i];
    if (u >= 0xD800 && u <= 0xDBFF) {                  // 高代理,必须跟低代理
        if (i + 1 >= s.size()) return -1;
        const auto lo = s[i + 1];
        if (lo < 0xDC00 || lo > 0xDFFF) return -1;
        i += 2;
        return 0x10000 + ((u - 0xD800) << 10) + (lo - 0xDC00);
    }
    if (u >= 0xDC00 && u <= 0xDFFF) return -1;         // 孤立低代理
    i += 1;
    return static_cast<std::int32_t>(u);
}

关键点总结:

  • UTF-8 通过首字节的前缀位(0、110、1110、11110)判断字符占用 1~4 字节;
  • UTF-16 通过 0xD800~0xDBFF(高代理)和 0xDC00~0xDFFF(低代理)拼接出 BMP 之外的码点;
  • 代理区(U+D800~U+DFFF)在 UTF-8 中禁止使用——所以"UTF-8 里出现 ED A0 BD 之类字节"一定是编码错乱或数据被错误转换过。

5.6 生产环境选型

  • ICU(icu::UnicodeString):功能最全,Unicode 事实标准库;
  • iconv:POSIX 系统的通用编码转换接口;
  • Boost.Locale / boost::nowide:前者封装 ICU,后者专治"Windows 下用 UTF-8 调窄字符 API"的痛;
  • 平台 API:Windows 用 MultiByteToWideChar,Linux 直接处理 UTF-8 字节(多数场景根本不用转)。

六、平台差异与经典陷阱

6.1 Windows:系统语言是 UTF-16

Windows 内核与 Win32 API 的 Unicode 接口(CreateFileW、MessageBoxW、std::filesystem::path 内部表示)全部使用 UTF-16。因此 Windows 原生开发中,std::wstring 是"系统语言",std::string 反而是"外来户"。老式 A 结尾 API(CreateFileA)在中文系统上默认按 GBK 解释窄字符串,是乱码高发区。

6.2 Linux:UTF-8 是事实标准

Linux 的文件系统、终端、绝大多数库默认 UTF-8。在这里 std::string(UTF-8 字节)就是通用语言,wchar_t(4 字节 UTF-32)反而笨重且生态稀疏。很多 Linux 老手多年不用 wchar_t,也是这个原因。

6.3 经典陷阱逐个看

陷阱 1:strlen / size() 数的是字节

std::string s = "中文";          // UTF-8
std::cout << s.size();           // 6,不是 2
std::cout << s[0];               // 0xE4,一个"半截字符",直接输出是乱码

对 UTF-8 字符串按下标遍历、substr 截断,都可能把多字节字符拦腰截断,产生"�"。

陷阱 2:UTF-16 的"字符数"也不可靠

emoji 😀(U+1F600)在 UTF-16 中是 2 个编码单元(代理对)。std::wstring(L"😀").size() 返回 2,wcslen 同理。而且用户感知的"字符"(字素簇,如 👍🏻 肤色变体、组合音标)往往由多个码点组成——所以"数字符个数"这件事,永远比想象中复杂。

陷阱 3:GBK 字节被当 UTF-8 解码

网络、文件、数据库三方编码不一致时,最常见的乱码就是"把 GBK 字节当 UTF-8 读"。这类乱码的特征是出现大量 � 或"锟斤拷"(GBK 的 EF BF BD 反复解码的产物)。

陷阱 4:控制台编码与程序编码不一致

#include <iostream>
int main() {
    std::cout << "中文\n";   // Linux 终端 OK;Windows 老控制台默认 GBK,若程序输出 UTF-8 则乱码
}

Windows 解决手段:chcp 65001 切换控制台到 UTF-8;或程序启动时 SetConsoleOutputCP(CP_UTF8);新系统可在清单中声明 activeCodePage="UTF-8"。

陷阱 5:wchar_t 宽度移植

把 L"中文" 的 sizeof(wchar_t) 当 2 写死(Windows 习惯)的代码,到 Linux 上会出错。跨平台代码应避免直接处理 wchar_t,或统一用 char16_t/char32_t 这类尺寸确定的类型。

七、现代 C++ 的最佳实践(2026 视角)

7.1 原则一:UTF-8 Everywhere

社区经过多年踩坑,形成了共识:程序内部与数据交换层统一使用 UTF-8(std::string / C++20 的 std::u8string),只在系统边界(Windows API、文件系统)处转换成目标编码。理由:

  • UTF-8 兼容 ASCII,对英文零开销,无字节序问题;
  • 是文件、网络、数据库、终端的通用语言,几乎无需再转;
  • char8_t(C++20)从类型上防止与普通窄字符串混用。

7.2 原则二:利用 C++20/23 的新工具

  • C++20 char8_t / std::u8string:编码意图进入类型系统,编译期拦截混用;
  • C++20 std::u8string_view 等 view 类型:零拷贝读取 UTF-8 数据;
  • C++23 std::text_encoding(P1885 提案):首次把"当前字面量/环境的编码"标准化,可以查询 std::text_encoding::literal() 拿到执行字符集信息,为运行时编码判断提供标准依据。注意它只负责"识别/查询"编码,不做转换,具体支持程度随编译器版本而异,使用前请确认工具链。

7.3 一个完整的跨平台姿势

// 内部统一 UTF-8(std::string);Windows 边界处转 wchar_t
#ifdef _WIN32
std::wstring to_native(const std::string& utf8) { return Utf8ToWide(utf8); }   // 见 5.4
#else
const std::string& to_native(const std::string& utf8) { return utf8; }         // Linux 直接透传
#endif

同时遵循三条纪律:

  1. 源码统一保存为 UTF-8(Windows 侧加 /utf-8 编译选项);
  2. 内存中统一 std::string 存 UTF-8,禁止混用 wstring;
  3. 只在调用系统 API 的那一行做转换,转换函数集中封装、便于审计。

八、总结:一张决策表

场景推荐类型原因
跨平台文件、网络、序列化、日志std::string / std::u8string(UTF-8)通用语言,兼容性好
Windows 原生 API(Win32/WinRT)边界处转 std::wstring(UTF-16)系统内部就是 UTF-16
需要按码点随机访问std::u32string每个码点固定一个单元
仅存英文/ASCIIstd::string最省空间
与 ICU 等库交互按其要求的类型转换遵循宿主库约定

一句话版本:char 是字节,wchar_t 是"宽度随平台漂移"的宽字符,char16_t/char32_t 是编码固定的宽字符,char8_t 是"明确说自己是 UTF-8 的字节";宽窄的本质是编码单元宽度,乱码的根源是编码不匹配;现代 C++ 的最佳实践是内部统一 UTF-8、边界才转换。

如果你在实际开发中遇到过更离奇的乱码,或者对某个编码细节有疑问,欢迎在评论区讨论。

参考资料

  1. cppreference:Fundamental types(char / wchar_t / char16_t / char32_t 的尺寸与编码说明):https://en.cppreference.com/w/cpp/language/types
  2. cppreference:String literals(字面量前缀与编码规则):https://en.cppreference.com/w/cpp/language/string_literal
  3. cppreference:std::wstring_convert(C++17 弃用说明):https://en.cppreference.com/w/cpp/locale/wstring_convert
  4. cppreference:std::text_encoding(C++23):https://en.cppreference.com/w/cpp/text/text_encoding
  5. Microsoft Learn:/utf-8(源字符集与执行字符集选项):https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8
  6. GCC 文档:-finput-charset / -fexec-charset:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/afghjhg/article/details/166133561

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--