缺少带有 char* 等的“%p”的 GCC“-Wformat”警告

问题描述 投票:0回答:1

如果我使用 GCC 13.2.0 使用

-std=c17 -Wall -Wextra -Wpedantic
编译以下代码,尽管没有在与
void*
格式说明符对应的参数中使用
"%p"
,但我不会收到任何警告。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main()
{
    const char cstr[] = "ABC";
    size_t size = sizeof cstr;
    const uint8_t ustr[] = "ABC";
    const int8_t sstr[] = "ABC";
    const char* pcstr = cstr;
    const uint8_t* pustr = ustr;
    const int8_t* psstr = sstr;
    printf("cstr ptr:  %p\n", cstr);
    printf("size ptr:  %p\n", (void*)&size); // we need cast to prevent Wformat
    printf("&cstr ptr: %p\n", (void*)&cstr); // we also need this cast
    printf("pcstr:     %p\n", pcstr);
    printf("ustr ptr:  %p\n", ustr);
    printf("pustr:     %p\n", pustr);
    printf("sstr ptr:  %p\n", sstr);
    printf("psstr:     %p\n", psstr);
    return 0;
}

阅读完问答后*什么是警告以及如何解决警告:格式'%p'期望参数类型为'void *',但是参数2在打印时具有类型'int'[-Wformat=],我应该在这里期待未定义的行为吗?我尝试了几次搜索,但您会明白对于这样一个特定的组合来说,这些搜索有多困难。

是否可能是

void*

char-ish*
 共享某些属性 
I 缺失,或者这只是 GCC 中 缺失警告 的情况?希望这里有人能够阐明这个问题。

c compiler-warnings gcc-warning
1个回答
10
投票
在没有强制转换的情况下,您不会收到警告,因为

void *

 需要与指向字符类型的指针具有相同的表示形式,即 
char
signed char
unsigned char
,或任何type 是其中之一的 typedef。

这是由

C 标准第 6.2.5p28 节规定的

指向 void 的指针应具有相同的表示和对齐方式 要求作为指向字符类型的指针。

48)

    相同的表示和对齐要求旨在 暗示作为函数参数的可互换性,返回值 职能和工会成员。
这部分是由于 C 语言的历史早于

void *

 存在并且 
char *
 被用作通用指针类型。

但是,第 7.21.6.1p9 节有关

fprintf

 功能的规定:

如果转换规范无效,则行为为 不明确的。如果任何参数的类型不正确 相应的转换规范,行为未定义。

因此,虽然这实际上似乎是标准中未定义的行为,但 GCC(根据其发出的警告的性质)似乎允许在需要

char *

 作为扩展的地方使用 
void *
由于要求两种类型具有相同的表示。

所以我得出的结论是,这样的构造在 GCC 中是安全的,尽管在其他编译器上不一定。例如,可以想象,某些编译器可能会使用一种调用约定,将

void *

 传递给函数,而不是传递 
char *
,但考虑到表示要求,这似乎又是一种延伸。

事实上,第 7.16.1.1p2 节有关

va_arg

 宏的说明如下:

...如果没有实际的下一个参数,或者类型不兼容 与实际下一个参数的类型(根据 默认参数促销),行为未定义,除了 对于以下情况:

    一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,值可以表示为 两种类型;
  • 一种类型是指向 void 的指针,另一种是指向字符类型的指针。
因此,假设

fprintf

/
printf
 使用 
va_arg
 读取可变参数,行为 
由上述定义,但当然这是对
printf
函数族的行为做出假设。

在我看来,这是标准中的一个缺陷,应该解决该缺陷,以便明确定义此类转换。

© www.soinside.com 2019 - 2024. All rights reserved.