【问题标题】:How to set 2 byte wchar_t output?如何设置 2 字节 wchar_t 输出?
【发布时间】:2013-10-29 15:21:53
【问题描述】:

GCC 默认使用 4 字节的wchar_t。我可以设置选项-fshort-wchar 以在L"string constants" 中为每个wchar_t 获取2 个字节。但是当我将编译器选项设置为我的源文件时,我会收到著名的警告消息

foo.o 使用 2 字节 wchar_t 但输出是使用 4 字节 wchar_t;跨对象使用 wchar_t 值可能会失败

因为我真的想要 2 字节 wchar_t 我也希望输出使用这个变体。是否有任何链接器选项可以告诉它我想要什么?

编辑

此警告不会阻止链接器产生有效的输出。但数十条错误警告涵盖​​了其他信息。

【问题讨论】:

    标签: gcc ld binutils eabi


    【解决方案1】:

    在 binutils 中,您可以在 bfd/elf32-arm.c 中找到此错误消息:

    "警告:%B 使用 %u-byte wchar_t 但输出是使用 %u-byte wchar_t;跨对象使用 wchar_t 值可能会失败"

    但是,如果您进一步了解 binutils,您会发现输出的 wchar_t 大小并未在任何地方初始化为 4。那么是什么决定了“输出 wchar_t 大小”呢?实际上,给ld 的第一个对象初始化了输出属性。下一个对象将它们的属性合并到其中。如果你用 gcc/g++ 链接,它会在内部执行ld,所以试试gcc -v 看看ld 是如何执行的。这将使您深入了解它隐式链接到可执行文件的内部对象文件(除了您自己的)。

    例如,与 gcc 链接(例如gcc -v -shared -o libfoobar.so foo.o bar.o)会导致调用:

    ld ... crtbegin_so.o foo.o bar.o crtend_so.o ...

    即以下对象实际上是链接的(按顺序):

    • crtbegin_so.o(隐式)
    • foo.o
    • bar.o
    • crtend_so.o(隐式)

    这是 ld 的作用:

    1. 输出属性集一开始是空的。
    2. 合并 crtbegin_so.o 属性。现在输出属性包含out_attr[Tag_ABI_PCS_wchar_t] == 4
    3. 合并 foo.o 属性。如果 foo.o 是使用 -fshort-wchar 构建的,那么 in_attr[Tag_ABI_PCS_wchar_t] == 2 会导致冲突和您看到的警告。

    如果您要在 ld 命令行上交换 crtbegin_so.o 和 foo.o,则会收到以下警告:

    ld:警告: android-ndk-r9d/platforms/android-16/arch-arm/usr/lib/crtbegin_so.o 使用 4 字节 wchar_t 但输出是使用 2 字节 wchar_t;用于 跨对象的 wchar_t 值可能会失败

    如您所见,这不是输入与输出不兼容的问题,而是链接在一起的两个目标文件之间(感知到的)不兼容问题。

    我们能做些什么呢?

    • As of 2008ld 支持 --no-wchar-size-warning 标志来禁止此警告。但正如你所说,不分青红皂白地压制警告有其缺点。

    • 您可以使用 -fshort-wchar 重建工具链。

    • 如果你真的相信sizeof(wchar_t)-agnostic,你可以从你的内部gcc对象二进制文件中去掉Tag_ABI_PCS_wchar_t标签。这可能比重建工具链更容易。为此,您可以使用我曾经写过的this utility。 (您可能需要解压缩 libgcc.a,更改其目标文件并重新打包。)

    【讨论】:

    • +1 用于重建工具链。我猜你也需要一个 libc(++)。
    • AFAIK libstdc++ 是(仅)作为工具链 (g++) 的一部分构建的。
    【解决方案2】:

    这是一个警告,而不是错误。您可以忽略它,但如果您链接到使用 4 字节 wchar_t 编译的其他库,则会导致问题。如果您必须使用 2 字节的 wchar_t,那么您必须找到这些库的替代品或重新编译它们

    你也可以试试-fwide-exec-charset=UTF-16

    • -fwide-exec-charset=charset
      • 设置宽执行字符集,用于宽字符串和字符常量。默认为 UTF-32 或 UTF-16,以对应于 wchar_t 的宽度为准。与-fexec-charset 一样,charset 可以是系统的 iconv 库例程支持的任何编码;但是,您将遇到与wchar_t 不完全匹配的编码问题。

    如果你有 C11 支持,你可以使用 char16_t(带有 u 前缀作为字符串文字)并在必要时转换为 wchar_t

    【讨论】:

    • 虽然我没有写错误信息。当您收到一打这样的消息时,很难忽视。好吧,我替换了 wchar_t 函数实现。所以“那些库”都没有链接。所以问题仍然是“如何输出”。
    • 如果您想禁用警告,只需使用-wstackoverflow.com/questions/1079997/…
    • 好吧,我希望抑制 wchar_t 消息以查看其他可能更重要的警告。
    • 您可以选择性地禁用特定警告。查看我上面评论中的后一个链接
    • 您的链接指向“许多选项的名称以 ... 开头”,但也有一个答案带有指向 gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/… 的链接,但这控制编译器诊断,而有问题的警告由链接器。
    猜你喜欢
    • 1970-01-01
    • 2017-03-23
    • 2013-10-04
    • 2021-08-21
    • 2012-10-05
    • 2014-11-01
    • 2021-01-23
    • 1970-01-01
    相关资源
    最近更新 更多