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 期中。
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 期中。