7

GCC 默认使用 4 字节wchar_t。我可以设置选项-fshort-wcharwchar_tL"string constants". 但是当我将编译器选项设置为我的源文件时,我收到了著名的警告消息

foo.o 使用 2-bytewchar_t但输出是使用 4-byte wchar_twchar_t跨对象使用值可能会失败

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

编辑

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

4

2 回答 2

16

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

“警告:%B 使用 %u 字节 wchar_t 但输出是使用 %u 字节 wchar_t;跨对象使用 wchar_t 值可能会失败”

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

例如,与 gcc (eg 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
  • 酒吧.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 值可能会失败

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

我们对于它可以做些什么呢?

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

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

  • Tag_ABI_PCS_wchar_t如果你真的相信它们是不可知的,你可以从你的内部 gcc 对象二进制文件sizeof(wchar_t)中去除标签。这可能比重建工具链更容易。为此,您可以使用我曾经编写的这个实用程序。(您可能需要解压缩 libgcc.a,更改其目标文件并重新打包。)

于 2014-05-27T18:49:49.790 回答
1

这是一个警告,而不是错误。您可以忽略它,但如果您链接到使用 4-byte 编译的其他库,则会导致问题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在必要时转换为

于 2013-10-21T08:30:31.380 回答