c - 在c中使用宽字符时出现奇怪的空格

标签 c

我正在尝试绘制一个具有给定宽度和高度的正方形。 我试图在使用 Unicode 中的框字符时这样做。 我正在使用这段代码:

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

#include "string_prints.h"

#define VERTICAL_PIPE L"║"
#define HORIZONTAL_PIPE L"═"
#define UP_RIGHT_CORNER L"╗"
#define UP_LEFT_CORNER L"╔"
#define DOWN_RIGHT_CORNER L"╝"
#define DOWN_LEFT_CORNER L"╚"

// Function to print the top line
void DrawUpLine(int w){
    setlocale(LC_ALL, "");
    wprintf(UP_LEFT_CORNER);
    for (int i = 0; i < w; i++)
    {
        wprintf(HORIZONTAL_PIPE);
    }
    wprintf(UP_RIGHT_CORNER);
}

// Function to print the sides
void DrawSides(int w, int h){
    setlocale(LC_ALL, "");
    for (int i = 0; i < h; i++)
    {
        wprintf(VERTICAL_PIPE);
        for (int j = 0; j < w; j++)
        {
            putchar(' ');
        }
        wprintf(VERTICAL_PIPE);
        putchar('\n');
    }
}

// Function to print the bottom line
void DrawDownLine(int w){
    setlocale(LC_ALL, "");
    wprintf(DOWN_LEFT_CORNER);
    for (int i = 0; i < w; i++)
    {
        wprintf(HORIZONTAL_PIPE);
    }
    wprintf(DOWN_RIGHT_CORNER);
}

void DrawFrame(int w, int h){
    DrawUpLine(w);
    putchar('\n');
    DrawSides(w, h);
    putchar('\n');
    DrawDownLine(w);
}

但是当我使用一些 int 值运行此代码时,我得到的输出似乎是随机的空格和换行符(尽管管道看起来顺序正确)。

它是从 main.c 的 header 中调用的,如下所示:

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

#include "string_prints.h"

int main(){
    DrawFrame(10, 20); // Calling the function
    return 0;
}

正如您所见,我不明白 setlocale 的正确用法,您只需要执行一次吗?或更多?

如有任何帮助,请提前致谢!

最佳答案

Also as you can see I don't understand the correct use of setlocale, do you need to do it only once? or more?

通过setlocale()应用的区域设置更改在调用进程中是持久的。除非您想进行多次更改,否则不需要多次调用该函数。但是您确实需要为其命名一个能够满足您预期目的的语言环境,或者如果您使用空字符串调用它,那么您或程序用户确实需要确保定义各种环境的环境变量区域设置类别设置为适合目的的值。

But when I am running this code with some int values I get an output with seemingly random spaces and newlines.

这听起来像是字符编码不匹配的结果,甚至是两个(但另见下文):

  • 可能会出现运行时不匹配的情况,因为您告诉程序用于输出的区域设置与显示程序输出的输出设备(例如终端)所期望的区域设置不匹配,和
  • 源文件的实际字符编码与编译器解释为具有的编码之间也可能存在编译时不匹配的情况。

此外,尽管使用了宽字符串文字语法,但源代码中可能出现 C 基本集以外的字符仍取决于实现。宽语法主要指定文字的存储形式(wchar_t 类型的元素),而不是指定哪些字符值有效或如何解释它们。

另请注意,wchar_t 的宽度取决于实现,并且可以小至八位。 wchar_t 不一定可以表示任意 Unicode 字符 - 事实上,wchar_t 很常见为 16 位宽,这实际上对于 Unicode 21 位代码空间中的大多数字符来说不够宽。您可能会以两个单元的形式获得较宽字符的内部表示,例如 UTF-16 代理对,但您也可能不会 - 其中很大一部分留给单独的实现。

其中,编译器期望什么编码、在什么情况下以及如何影响这些都取决于实现。例如,对于 GCC,默认源(“输入”)字符集是 UTF-8,您可以通过其 -finput-charset 选项定义不同的字符集。如果您愿意,还可以通过 -fexec-charset 和 -fwide-exec-charset 选项指定标准执行字符集和宽执行字符集。 GCC 在编译时(源字符集到执行字符集)和运行时(从执行字符集到语言环境字符集)都依赖 iconv 进行转换。其他实现有其他选项(或没有),具有自己的语义。

那么你应该做什么? 首先,我建议通过使用仅使用基本字符集(需要 C2011)表示的 UTF-8 字符串文字来将源字符集排除在外:

#define VERTICAL_PIPE     u8"\xe2\x95\x91"
#define HORIZONTAL_PIPE   u8"\xe2\x95\x90"
#define UP_RIGHT_CORNER   u8"\xe2\x95\x97"
#define UP_LEFT_CORNER    u8"\xe2\x95\x94"
#define DOWN_RIGHT_CORNER u8"\xe2\x95\x9d"
#define DOWN_LEFT_CORNER  u8"\xe2\x95\x9a"

请注意,生成的字符串是普通字符串,而不是宽字符串,因此您不应将面向宽的输出函数与它们一起使用。相反,请使用普通的 printfputchar

这给我们带来了代码的另一个问题:在不采取明确的切换措施的情况下,不得将面向宽域和面向字节的函数混合写入同一流 (freopenfwide;请参阅标准的 paragraph 7.21.2/4)。在实践中,将两者混合可能会产生困惑的结果。

然后还要确保您的本地环境变量针对您的实际环境正确设置。可能性很大,但值得一试。

关于c - 在c中使用宽字符时出现奇怪的空格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57083259/

相关文章:

c++ - 复制数组会修改使用原始数组的函数的行为

c++ - 将 C++ 添加到复杂的 C 生成文件

c - 打印机端口编码教程

c - 这个二维数组通过测试怎么会失败?

c - 为什么我在 GDB 中收到消息 "Single-stepping until exit . . . which has no line number information"?

c - 无需外部工具即可获取系统总内存

c - 将二进制字符串作为二进制文件写入文件

c - ANSI C - 不使用数组替换空白字符

通过使用结构不同的代码将管理器与C程序联系起来

c - 如何使用 getch() (来自 curses 库)?