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

svujldwt  于 2023-02-03  发布在  其他
关注(0)|答案(3)|浏览(183)

我必须将配置信息写入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]#
fkaflof6

fkaflof61#

有没有一种优雅的方法可以只用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的语言环境。

tjjdgumg

tjjdgumg2#

要可靠而优雅地获取UTF-8字符串,而不管源文件编码如何,可以添加u8 prefix

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

可以将char str[]更改为char8_t str[] if you use C++20
这样你就不需要找到编码的UTF-8字节,当你需要另一种编码如UTF-16或UTF-32时,只需改变类型和前缀(u8uUchar[]auto),编译器会自动转换编码以保证内存中的字节序列正确

pexxcrt2

pexxcrt23#

我没有使用wchar_t,而是使用了char数组,对吗?
char的默认字符集和编码是实现定义的(可以是EBCDIC、ASCII、UTF-8或源文件碰巧使用的任何字符集或其他字符集),wchar_t的默认字符集和编码也是实现定义的(可以是UTF-16 LE或...)。
如果您需要输出为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这样的实用程序对使用所需字符集和编码的文本文件)。

相关问题