C++如何在运行时复现编译期的十六进制转义字符串解析效果
问题解答
基础规则答疑
- 反引号
的解析规则:在双引号包裹的C字符串字面量中,反引号不属于需要转义的特殊字符,编译器会直接保留其原始值,对应ASCII码0x60`,无额外转换。 \a与\x转义的区别:二者都属于编译期生效的C字符串转义序列,逻辑类似但规则不同:\a是C标准预定义的单字符转义,直接映射为ASCII响铃字符,值固定为0x07,和\x07的编译结果完全一致。\x是通用十六进制转义前缀,后面可以跟1~2位十六进制数字(char为8位场景下),编译器会直接将其转换为对应数值的字节写入字符串内存。
GCC编译\x转义的实际输出逻辑
默认编译配置下,GCC对\x转义的处理完全遵循C标准:取\x后连续的十六进制字符(0-9、a-f、A-F),转换为对应整数后,截断为char类型的宽度(通常为8位),直接作为字节存入字符串的只读数据段,不会做任何编码转换。
你给出的字符串字面量"\xf1\xf8\a\\x9cT\x82z\x18\x5\xb9\xbc\x80\xca\x15"编译后,对应的二进制字节序列为(十六进制表示): f1 60 f8 07 5c 9c 54 82 7a 18 05 b9 bc 80 ca 15`
运行时解析同格式字符串的实现方案
以下是可直接使用的C语言实现,输入为和源码格式完全一致的字符串,输出为和编译期解析结果完全一致的二进制数组:
#include <stdio.h> #include <stdint.h> #include <ctype.h> #include <string.h> // 输入:src 为源码格式的输入字符串,dst 为输出二进制缓冲区,dst_len为缓冲区大小 // 返回值:解析后的二进制长度,返回-1表示缓冲区不足 int parse_c_string_literal(const char *src, uint8_t *dst, size_t dst_len) { size_t src_idx = 0, dst_idx = 0; size_t src_len = strlen(src); while (src_idx < src_len) { if (dst_idx >= dst_len) return -1; if (src[src_idx] != '\\') { dst[dst_idx++] = src[src_idx++]; continue; } // 处理转义字符 src_idx++; if (src_idx >= src_len) { dst[dst_idx++] = '\\'; break; } switch (src[src_idx]) { case 'a': dst[dst_idx++] = 0x07; src_idx++; break; case 'b': dst[dst_idx++] = 0x08; src_idx++; break; case 'f': dst[dst_idx++] = 0x0c; src_idx++; break; case 'n': dst[dst_idx++] = 0x0a; src_idx++; break; case 'r': dst[dst_idx++] = 0x0d; src_idx++; break; case 't': dst[dst_idx++] = 0x09; src_idx++; break; case 'v': dst[dst_idx++] = 0x0b; src_idx++; break; case '\\': dst[dst_idx++] = 0x5c; src_idx++; break; case '\'': dst[dst_idx++] = 0x27; src_idx++; break; case '"': dst[dst_idx++] = 0x22; src_idx++; break; case '?': dst[dst_idx++] = 0x3f; src_idx++; break; case 'x': { // 处理\x转义,取最多2位十六进制 src_idx++; uint8_t val = 0; int cnt = 0; while (cnt < 2 && src_idx < src_len && isxdigit(src[src_idx])) { char c = tolower(src[src_idx]); val = val * 16 + (c >= 'a' ? c - 'a' + 10 : c - '0'); src_idx++; cnt++; } if (cnt == 0) { // \x后没有十六进制字符,保留\x原样 dst[dst_idx++] = '\\'; dst[dst_idx++] = 'x'; } else { dst[dst_idx++] = val; } break; } default: // 其他未定义转义,保留原样 dst[dst_idx++] = '\\'; dst[dst_idx++] = src[src_idx++]; break; } } return dst_idx; }
调用示例:
int main() { const char *input = "\\xf1`\\xf8\\a\\\\\\x9cT\\x82z\\x18\\x5\\xb9\\xbc\\x80\\xca\\x15"; uint8_t buf[32] = {0}; int len = parse_c_string_literal(input, buf, sizeof(buf)); for (int i = 0; i < len; i++) { printf("%02x ", buf[i]); } return 0; }
以上代码输出的二进制序列和你给出的编译期字符串字面量的内存数据完全一致。
内容的提问来源于stack exchange,提问作者RedMarsBlueMoon
相关产品推荐
相关产品推荐

