如果我用CC 13.2.0用-std=c17 -Wall -Wextra -Wpedantic编译下面的代码,尽管在对应"%p"个格式说明符的参数中没有使用void*,但我不会收到警告.

#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;
}

读完问答*What is and how to solve the warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int ’ [-Wformat=] when printing it out后,我应该期待这里的undefined behavior吗?我try 了几次搜索,但您会明白对于如此特定的组合来说,这些搜索有多么困难.

void*char-ish*是否共享上午I点失踪的一些房产,或者这只是海湾合作委员会中missing warnings的 case ?希望这里的有人能够就这个问题提供一些线索.

推荐答案

在没有强制转换的情况下,您不会收到警告,因为void *需要与指向字符类型(即charsigned charunsigned char)或任何类型的typedef类型的指针具有相同的表示.

这由C standard条中的6.2.5第28节规定:

指向无效的指针应具有相同的表示和对齐方式 要求作为字符类型的指针.48)

  1. 相同的表示和对齐要求旨在 隐含可执行性作为函数参数,返回值 职能和unions 成员.

这在一定程度上是由于C语言的历史,直到void *存在和char *被用作通用指针类型之前.

然而,关于fprintf个功能的第7.21.6.1p9节规定:

如果转换规范无效,则行为为 未定义.如果任何参数不是 相应的转换规范,行为未定义.

因此,虽然这似乎实际上是标准字面上未定义的行为,但由于两种类型的要求,GCC(根据其给出的警告的性质)似乎允许在预期void *作为扩展的地方使用char *.具有相同的表示.

因此,我的结论是,此类 struct 在海湾合作委员会中是安全的,尽管在其他编译器上不一定. 例如,可以想象,一些编译器可能会使用将void *传递给函数的调用约定与传递char *的方式不同,但鉴于表示要求,这似乎是一种延伸.

事实上,关于va_arg个宏的第7.16.1.1p2节规定了以下内容:

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

  • 一种类型是有符号的integer类型,另一种类型是相应的无符号的integer类型,并且该值可以表示为 两种类型;
  • one type is pointer to void and the other is a pointer to a character type.

因此,假设fprintf/printf使用va_arg来读取可变参数,则行为would由上面定义,但当然这是对printf函数族的行为做出假设.

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

C++相关问答推荐

通过MQTT/蚊子发送大文件—限制在4MB

为什么写入系统调用打印的字符数不正确?

MISRA C:2012 11.3违规强制转换(FLOAT*)到(uint32_t*)

将 typewriter LF打印到Windows终端,而不是隐含的CR+LF

GCC预处理宏和#杂注GCC展开

如果包含路径不存在,我的编译器可以被配置为出错吗?(GCC、MSVC)

将 struct 变量赋给自身(通过指针取消引用)是否定义了行为?

Win32API Wizzard97 PropSheet_SetWizButton不工作

双指针指向常量双指针的指针类型赋值不兼容

Kdb:仅升级指定的列

为什么我的Hello World EFI程序构建不正确?

在句子中转换单词的问题

在for循环中指向数组开头之前

合并对 struct 数组进行排序

表达式x&;&;(~x)应该返回1还是0?它依赖于编译器吗?

通过char*访问指针的对象表示是未定义的行为吗?

";错误:寄存器的使用无效;当使用-masm=intel;在gcc中,但在AT&;T模式

C11 嵌套泛型

我该如何处理这个 C 90 代码中的内存泄漏?

如何在C中以0x格式打印十六进制值