如何解决“格式中未知的转换类型字符'z'"的问题,特定于编译器的警告? [英] How do I work around the "unknown conversion type character `z' in format" compiler-specific warning?

查看:890
本文介绍了如何解决“格式中未知的转换类型字符'z'"的问题,特定于编译器的警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理交叉编译到几种目标体系结构的代码.

我看了 of minGW有关,因此这些答案(本质上是ifdef反对_WIN32)不适用于我的基本相同问题的实例,即printf无法识别"%zu"作为格式说明符用于size_t,但带有mips交叉编译器.

是否存在一个现有的编译器标志(用于指定的交叉编译器),它使libc能够将%zu"识别为size_t的格式说明符?

$ cat ./main.c
// main.c

#include <stdio.h>

int main( int argc, char* argv[] )
{
  size_t i = 42;
  printf( "%zu\n", i );
  return 0;
}

$ /path/to/mips_fp_le-gcc --version
2.95.3
$ 
$ file /path/to/libc.so.6
/path/to/libc.so.6: ELF 32-bit LSB pie executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 2.2.15, not stripped, too many notes (256)
$ 
$ /path/to/mips_fp_le-gcc -mips2 -O2 -EL -DEL -pipe -Wall -Wa,-non_shared -DCPU=SPARC -DLINUX -D_REENTRANT -DPROCESS_AUID -DTAGGING -fPIC -I. -I../../../root/include -I../include -I../../../common/include -I../../..
/root/include  -DDISABLE_CSL_BITE -DDISABLE_DNS_LOOKUP     -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES  -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES  -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_C
SL_DUPLICATES  -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES -o ./main.o -c main.c 
main.c: In function `main':
main.c:6: warning: unknown conversion type character `z' in format
main.c:6: warning: too many arguments for format

如果对粗体问题的直接回答是否",还有什么其他可能的解决方案?想到的可能性是...

  1. register_printf_function()
  2. 将格式说明符包装在特定于目标的宏中(类似于cc1: unknown C standard 'c99'"

    解决方案

    您的gcc不支持z作为长度修饰符.与MIPS无关,它完全没有区别,但是2.95.3版缺少支持.

    在1998年2月9日添加了对Z长度修饰符的支持,由Andreas Schwab提交,"c-common.c(format_char_info):添加新字段zlen.".在此之前,Z有一个gcc扩展作为size_t的转换类型说明符(而不是长度修饰符).该代码在gcc 2.95.3中,因此它应该识别Z,但不能识别z.

    约瑟夫·迈尔斯(Joseph Myers)于2000年7月17日添加了对z的支持,"c-common.c(scan_char_table):在diouxXn格式上允许"z"个长度修饰符".尽管时间早于gcc 2.95.3,但它在gcc 3分支中,直到gcc 3.0才发布.因此,您的古老编译器根本就没有.

    因此您可以将代码更改为使用Z,但仍受支持.您还可以根据编译器版本定义宏:

    #if __GNUC__ < 3
    #define PZ "Z"
    #else
    #define PZ "z"
    #endif  
    

    然后像printf("The size is %"PZ"u\n", sizeof(int));中一样使用它,您仍然必须修改代码.但这最后没有什么不同,因为预处理器之后的格式字符串在新的编译器上仍为%zu,在旧的编译器上为%Zu.将size_t参数强制转换为其他变量的想法实际上会更改代码的结果,因为在某些情况下,根据size_t是什么以及您强制转换为哪种类型,将它们转换为较大/较小的类型.

    或者,如果您可以构建工具链,则可以修补gcc以了解z.我认为在case语句中使用"c-common.c"中的zlen进行单行更改即可.

    register_printf_function()是glibc的一部分,glibc是printf()代码所在的位置.它将允许您在运行时以新格式扩展printf.在编译时您无法做任何改变编译器的事情.而且我不相信gcc在使用register_printf_function()时进行printf类型检查时将无法知道已经添加了新格式.

    I'm working on code that is cross-compiled to several target architectures.

    I looked at the handful of hits from searching Stack Overflow for "printf size_t unknown conversion type character" warning, however those posts all seem to be related to minGW, so those answers, essentially ifdefing against _WIN32, do not apply to my instance of essentially the same problem, i.e. printf not recognizing "%zu" as the format-specifier for size_t, but with a mips cross compiler.

    Is there an existing compiler flag (for the noted cross-compiler) that enables libc to recognize "%zu" as the format-specifier for size_t?

    $ cat ./main.c
    // main.c
    
    #include <stdio.h>
    
    int main( int argc, char* argv[] )
    {
      size_t i = 42;
      printf( "%zu\n", i );
      return 0;
    }
    
    $ /path/to/mips_fp_le-gcc --version
    2.95.3
    $ 
    $ file /path/to/libc.so.6
    /path/to/libc.so.6: ELF 32-bit LSB pie executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 2.2.15, not stripped, too many notes (256)
    $ 
    $ /path/to/mips_fp_le-gcc -mips2 -O2 -EL -DEL -pipe -Wall -Wa,-non_shared -DCPU=SPARC -DLINUX -D_REENTRANT -DPROCESS_AUID -DTAGGING -fPIC -I. -I../../../root/include -I../include -I../../../common/include -I../../..
    /root/include  -DDISABLE_CSL_BITE -DDISABLE_DNS_LOOKUP     -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES  -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES  -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_C
    SL_DUPLICATES  -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES -o ./main.o -c main.c 
    main.c: In function `main':
    main.c:6: warning: unknown conversion type character `z' in format
    main.c:6: warning: too many arguments for format
    

    If the direct answer to the bolded question is "no", what are other possible solutions? Possibilities that come to mind are...

    1. register_printf_function()
    2. Wrap the format-specifier in a target-specific macro (similar to this minGW-specific post)

    ...any other ideas? I'd have a strong preference for solutions not involving target-specific preprocessor code, for which reason the above two are not ideal.

    I think (but am not sure) that the cross-compiler version is old; are newer versions of the noted toolchain known/guaranteed to have a libc that recognize "%zu" as the format-specifier to size_t?


    Update: This cross-compiler seems to not recognize -std=c99; adding it to the compiler flags generates the error "cc1: unknown C standard 'c99'"

    解决方案

    Your gcc does not support z as a length modifier. It's nothing to do with MIPS, which makes no difference at all, but rather that version 2.95.3 lacks support.

    Support for a Z length modifier was added on Feb 9th 1998, commit by Andreas Schwab "c-common.c (format_char_info): Add new field zlen.". There was a gcc extension of Z as a conversion type specifier (rather than length modifier) for size_t before that. This code is in gcc 2.95.3, so it should recognize Z, but not z.

    Support for z was added on July 17 2000 by Joseph Myers, "c-common.c (scan_char_table): Allow "z" length modifiers on diouxXn formats". Despite predating gcc 2.95.3 in time, this was in a gcc 3 branch and wasn't released until until gcc 3.0. So your ancient compiler simply hasn't got it.

    So you could change your code to use Z, which is still supported. You could also define a macro based on compiler version:

    #if __GNUC__ < 3
    #define PZ "Z"
    #else
    #define PZ "z"
    #endif  
    

    Then use this as in printf("The size is %"PZ"u\n", sizeof(int)); You'll still have to modify your code. But it wouldn't be any different in the end, as the format string, after the preprocessor, would still be %zu on newer compilers and %Zu on old ones. The idea of casting the size_t arguments to something else will actually change the result of the code, as they will be cast to larger/smaller types in some cases, depending on what size_t is and what you cast to.

    Alternatively, if you can build your toolchain, you could patch gcc to know about z. I think a one line change in the case statement that uses zlen in "c-common.c" would do it.

    register_printf_function() is part of glibc, which is where the printf() code lives. It would allow you to extend printf with new formats at run time. There's nothing you could do at compile time with it that will change the compiler. And I don't believe gcc will be able to know that a new format has been added when it does printf type checking when register_printf_function() is used.

    这篇关于如何解决“格式中未知的转换类型字符'z'"的问题,特定于编译器的警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆