Windows中C语言与Java的汉字编码问题

你是否遇到过C语言或者Java程序中的汉字字符串输出为乱码的现象,也许你去查询过解决办法,得到的结论就是简单地把源码文件转换为GBK编码存储,然而并未深思其中的原因。本文会解释其原因以及正确的应对方式(不转换源码的编码)。首先明确本文的操作环境:Windows操作系统(中文)、C语言编译器为MinGW-GCC。下面给出两个示例程序:

// a.c(utf-8)
#include <stdio.h>

int main(void)
{
    printf("%s", "你好");
    return 0;
}
// a.java(utf-8)

public class a {
    public static void main(String[] args) {
        System.out.println("你好");
    }
}

以上源码文件均使用UTF-8编码,然后我们打开PowerShell,编译两个文件:gcc a.cjavac a.java,然后运行:.\a.exejava a,会发现输出的均不是“你好”,而是乱码的“浣犲ソ”。实际上,以UTF-8编码的“你好”和以GBK编码的“浣犲ソ”的二进制序列是一样的(E4 BD A0 E5 A5 BD),你发现其中端倪了吗?

Read More »

C语言与C++中关于内联函数的陷阱

C语言的内联函数默认为内部链接,所以不阻止其他文件定义同名外部函数。但如果在其他文件中定义了同名外部函数,则在定义内联函数的文件中调用此函数属于未指定行为,该调用可能会调用外部函数。

注意由于在一个文件中调用函数前需要声明,并且该声明不能和定义冲突,所以即便外部函数与内联函数的原型不同,也做不到在定义内联函数的文件中声明此外部函数,因为对外部函数的声明会和内联函数的定义冲突。此时如果在定义内联函数的文件中又实际调用了外部函数,则调用形式不满足外部函数的实际定义,行为更加危险。

Read More »

C语言数组的范围初始化器

C89标准中,对数组进行初始化时,初始化列表未写全的部分会进行默认初始化,比如:char a[10] = {1, 1, 1};那么数组a中只有前三个元素会被初始化为1,后面7个元素则被默认初始化为0。

C99增加了指定初始化器(designated initializer)的特性:char a[10] = {[5] = 1};那么数组元素a[5]会被初始化为1,其余元素则默认为0。

gcc编译器(包括mingw)对“指定初始化器”语法进行了扩展从而支持“范围初始化器”语法:char a[10] = {[0 ... 4] = 1, [5] = 2, [7 ... 9] = 3};那么a[0]~a[4]=1,a[5]=2,a[6]默认=0,a[7]~a[9]=3。注意“…”两侧都必须有空格。

Read More »