clang 是否支持格式字符串 %ms 以便 scanf() 分配缓冲区?

Does clang support format string %ms so scanf() allocates the buffer?

scanf("%ms", &s) 应该在 clang 中工作吗?

app.c:

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

int main() {
    char *s;
    int ret = scanf("%ms", &s);
    if (ret) {
      printf("%d %s\n", ret, s);
      free(s);
    }
    else {
      printf("NO!\n");
    }
}
$ clang ./app.c && echo abc | ./a.out
NO!
$ clang --version
Apple clang version 12.0.5 (clang-1205.0.22.11)

在我的 macOS 上安装 gcc 结果相同,但它似乎在内部使用 clang。

在 Linux 使用 gcc,scanf 成功:

1 abc

来自 gcc man scanf:

  Each conversion specification in format begins with either the
  character '%' or the character sequence "%n$" (see below for the
  distinction) followed by:
   -     An optional 'm' character.  This is used with string
         conversions (%s, %c, %[), and relieves the caller of the
         need to allocate a corresponding buffer to hold the input:
         instead, scanf() allocates a buffer of sufficient size,
         and assigns the address of this buffer to the
         corresponding pointer argument, which should be a pointer
         to a char * variable (this variable does not need to be
         initialized before the call).  The caller should
         subsequently free(3) this buffer when it is no longer
         required.

这很令人困惑,因为如果我通过删除第二个参数 & 来破坏类型,那么 clang 会发出警告;它认识到 %ms 需要一个指向 char*:

的指针
./app.c:5:28: warning: format specifies type 'char **' but the argument has type 'char *' [-Wformat]
    int ret = scanf("%ms", s);
                     ~~~   ^
                     %s

尽管编译器警告可以识别 %ms 语法,但编译后的代码不支持它。

运行 man scanf BSD 手册没有记录 m 字符。

Compiler is not the C standard library. It's way more diversified. clang, gcc, msvc and others are compilers. glibc, musl and others are C standard library implementations, and they come with scanf() function implementation and may or may not support %m assignment-allocation character extension. The %m is non-standard, as in it is not specified in the C language standard.

Does clang support format string %ms so scanf() allocates the buffer?

clang是一个编译器,它编译代码。从字面上看,clang 支持将任何内容传递给 scanf() 函数,包括任何格式说明符。 clang 编译代码并创建可执行文件。

您还发现,当为 %ms scanf 格式说明符提供无效参数类型时,clang 作为编译器支持诊断这种情况。从这个意义上讲,clang 警告支持此格式说明符。

比方说,“if clang supports %m specifier”这个问题就像是问汽车轮胎是否可以开得很快。好吧,从字面上看它可以,但它取决于引擎(C 标准库),如果你的车会很快或不快(支持或不支持说明符)。 (糟糕的寓言,但希望它只是说明了答案的要点)。

on my macOS

据我了解,在 macOS 上使用 BSD libc C 标准库实现。如您所知,this implementation of scanf() function 不支持 m 扩展名。

m 扩展很可能首先在 GNU C 库中实现。我看到它已添加到 POSIX scanf 规范的第 7 期中。