使用fopen / write时汉字出现问题

时间:2019-09-26 04:46:33

标签: c unicode encoding file-io

我必须将配置信息写入Linux中的文件,而配置信息包含汉字。

我不是使用wchar_t,而是使用char数组,这是正确的吗?

这是我的代码:

code in paster.ubuntu

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#define MSG_LEN 4096

int save_config_info(const char *path, char* message)
{
    FILE *fp = NULL;

    fp = fopen(path, "wb");
    if (!fp)
    {
            //print error message
        return -1;
    }

    if (fwrite(message, 1, strlen(message), fp) != strlen(message)) 
        {
        //print error message
        fclose(fp);
        return -1;
    }

    fclose(fp);
    return 0;
}

int main()
{
    //config contain chinese character
    char str[MSG_LEN] = "配置文件中包含中文";
    char path[PATH_MAX] = "example.txt";
    save_config_info(path,str);

    return 0;
}

如果源代码编码为ISO-8859-1,则生成example.txt并使用cat来显示??

但是使用utf-8更改源代码编码,一切正常。

我的问题是:

因为我不能确保源文件的编码,所以有什么优雅的方式来处理汉字。

我希望example.txt看起来总是正确的。

[root workspace]#file fork.c
fork.c: C source, ASCII text
[root workspace]#gcc -g -o fork fork.c
[root workspace]#
[root workspace]#./fork
[root workspace]#
[root workspace]#
[root workspace]#file example.txt
example.txt: ASCII text, with no line terminators
[root workspace]#
[root workspace]#cat example.txt
?????????[root workspace]#
[root workspace]#
[root workspace]#
[root workspace]#file fork.c
fork.c: C source, UTF-8 Unicode text
[root workspace]#
[root workspace]#gcc -g -o fork fork.c
[root workspace]#./fork
[root workspace]#
[root workspace]#file example.txt
example.txt: UTF-8 Unicode text, with no line terminators
[root workspace]#cat example.txt
配置文件中包含中文[root workspace]#

3 个答案:

答案 0 :(得分:1)

是否存在仅使用ASCII字符来表示ASCII中找不到的字符的优雅方法?不。

但是有可能以微不足道的方式做到这一点。

char str[MSG_LEN] = "\xE9\x85\x8D\xE7\xBD\xAE\xE6\x96\x87\xE4\xBB\xB6\xE4\xB8\xAD\xE5\x8C\x85\xE5\x90\xAB\xE4\xB8\xAD\xE6\x96\x87";

当然,就像您的原始程序一样,这假定查看文件名的人员(例如,使用ls)的语言环境基于UTF-8。

答案 1 :(得分:0)

  

我不使用wchar_t,而是使用char数组,这对吗?

我会拒绝。 char的默认字符集和编码是由实现定义的(可以是EBCDIC或ASCII或UTF-8或碰巧使用的源文件或其他任何东西),而wchar_t的默认字符集和编码是也是实现定义的(可以是UTF-16LE或...)。

如果需要输出为UTF-8;然后(特别是对于可移植代码),您需要忽略C编译器的随机默认值。您还应该避免使用char,因为无论是有符号的还是无符号的都是实现定义的,请避免使用unsigned char,因为实际上并不能保证它是8位的,并且避免使用wchar_t(因为它的大小是实现定义)

具体来说(对于UTF-8),我将使用uint8_t,例如:

uint8_t str[] = 0xE9, 0x85, 0x8D, 0xE7, 0xBD, 0xAE, 0xE6, 0x96, 0x87, 0xE4, 0xBB, 0xB6,
                0xE4, 0xB8, 0xAD, 0xE5, 0x8C, 0x85, 0xE5, 0x90, 0xAB, 0xE4, 0xB8, 0xAD,
                0xE6, 0x96, 0x87, 0x00;

当然,如果您希望文件包含CNS-11643(或其他任何文件),也可以这样做。您只需要找到一个合适的类型,然后找到“该类型的数字数组”(例如,可以在使用所需字符集和编码的文本文件上使用类似hexdump的实用程序)。

答案 2 :(得分:0)

要可靠地获取UTF-8字符串而不管使用哪种编码方式

char str[] = u8"\u914D\u7F6E\u6587\u4EF6\u4E2D\u5305\u542B\u4E2D\u6587";

char也可以是char8_t

通过这种方式,您无需找到已编码的UTF-8字节,并且在需要其他编码(例如UTF-16或UTF-32)时,只需将类型和前缀(u8更改为{{1 }}或u