如何在NASM字符串中正确打印非ASCII字符?
问题:NASM程序无法正确显示非ASCII特殊字符
我写了一个小型NASM程序,用来读取第一个命令行参数并打印输出。ASCII输入下运行正常,比如执行myfile hello会返回argv = hello,但输入包含õ、ä、ö、ü这类特殊字母时,显示结果会变成§、õ、÷、³。
当前代码如下:
section .data input dw `argv = %s\n` , 0 section .bss section .text global _main extern _printf _main: push ebp mov ebp,esp push esi mov esi, [ebp + 12] mov ebx, 1 mov eax, [esi + ebx * 4] push eax push input call _printf pop esi mov esp, ebp pop ebp ret
编译命令:
nasm -f win32 myfile.asm -o myfile.obj gcc -m32 myfile.obj -o myfile.exe
如何修改才能支持任意类型的输入?
编辑补充:
把终端代码页设为1252确实解决了示例里的问题,但我需要更通用的方案,比如还是没法正常打印西里尔字符。试过用Unicode代码页(65001),但它会忽略所有非ASCII字符;也直接试过代码页1251,此时õ、ä、ö、ü会被转成俄语的х、д、ц、ь,但输入实际斯拉夫字母时只输出问号。怎么正确解决这个问题?
解决方案
问题根源在于Windows下命令行参数编码、终端代码页与C标准库函数的编码不匹配。要实现通用Unicode支持,需切换到宽字符(UTF-16)处理流程,具体步骤如下:
1. 改用宽字符版本的入口和打印函数
Windows原生命令行参数为UTF-16编码,改用_wmain作为入口点,配合wprintf打印宽字符串,避免编码转换丢失信息。
修改后的NASM代码:
section .data input dw `argv = %ls\n`, 0 ; %ls 用于宽字符串格式化 section .bss section .text global _wmain ; 宽字符版本入口 extern _wprintf ; 宽字符版本printf _wmain: push ebp mov ebp, esp push esi mov esi, [ebp + 12] ; 获取宽字符版argv数组地址 mov ebx, 1 mov eax, [esi + ebx * 4] ; 取第一个命令行参数(宽字符串指针) push eax push input call _wprintf pop esi mov esp, ebp pop ebp ret
2. 配置终端支持Unicode输出
编译运行前,在命令行执行以下命令,将终端切换为UTF-8代码页:
chcp 65001
3. 编译命令保持不变
继续使用原编译命令即可:
nasm -f win32 myfile.asm -o myfile.obj gcc -m32 myfile.obj -o myfile.exe
原理说明
_wmain直接接收Windows系统传递的UTF-16编码命令行参数,跳过ANSI代码页转换环节,避免非ASCII字符丢失或乱码。wprintf会将UTF-16宽字符串转换为终端当前代码页(UTF-8)的编码输出,可正确显示所有Unicode字符,包括西里尔字母、特殊西欧字符等。
若需要更底层控制,也可直接调用Windows API的WriteConsoleW函数,直接向控制台输出UTF-16字符,完全绕过C标准库的编码转换。
内容的提问来源于stack exchange,提问作者tanler
相关产品推荐
相关产品推荐

