Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
既然我们有snprintf,为什么我们不';你没有snscanf吗?_C_Posix - Fatal编程技术网

既然我们有snprintf,为什么我们不';你没有snscanf吗?

既然我们有snprintf,为什么我们不';你没有snscanf吗?,c,posix,C,Posix,我有snprintf,它可以避免缓冲区溢出,但是为什么没有名为snscanf的函数呢 代码: 因此,我认为还需要一个snscanf。为什么我们只有snprintf? 请注意,fnprintf并不是唯一的,大多数数组函数都有一个安全的变体。在sscanf(s,format,…)中,扫描的字符数组是一个常量字符*。无法写入s。当s[i]为NUL时,扫描停止。几乎不需要n参数作为扫描的辅助限制 在sprintf(s,format,…)中,数组s是目标snprintf(s,n,format,…)确保数据

我有
snprintf
,它可以避免缓冲区溢出,但是为什么没有名为
snscanf
的函数呢

代码:

因此,我认为还需要一个
snscanf
。为什么我们只有
snprintf

请注意,fnprintf并不是唯一的,大多数数组函数都有一个安全的变体。

sscanf(s,format,…)
中,扫描的字符数组是一个
常量字符*
。无法写入
s
。当
s[i]
为NUL时,扫描停止。几乎不需要
n
参数作为扫描的辅助限制

sprintf(s,format,…)
中,数组
s
是目标
snprintf(s,n,format,…)
确保数据不会被写入
s[n]
或更高版本


有用的是对
sscanf()
转换说明符的标志扩展,以便在编译时轻松指定限制。(现在可以在下面以一种繁琐的方式使用动态格式或使用
sscanf(src,“%4s”,buf1)
完成)

这里是
将告诉
sscanf()
读取一个
size\t
变量,用于即将到来的字符串的大小限制。也许在C17


如今行之有效的笨重方法

char * src = "helloeveryone";
char buf1[5];
char format[1+20+1+1];
sprintf(format, "%%" "%zu" "s", sizeof(buf1) - 1);
sscanf(src, format, buf1);

不需要使用
snscanf()
,因为不需要写入第一个缓冲区参数。
snprintf()
中的缓冲区长度指定写入的缓冲区大小:

char buffer[256];

snprintf(buffer, sizeof(buffer), "%s:%d", s, n);
sscanf()
对应位置的缓冲区是以null结尾的字符串;不需要显式长度,因为您不打算写入它(在C99和C11中是
const char*restrict buffer

在输出中,您已经需要指定字符串的长度(尽管如果使用
%s
而不是
%99s
或任何严格合适的方法,您可能占大多数):

如果您可以像使用
snprintf()
一样使用
%*s
,这将非常好/有用,但是您不能-在
sscanf()
中,
*
表示“不分配扫描值”,而不是长度。请注意,您不会编写
snscanf(src,sizeof(buf1),“%s”,buf1)
,这主要是因为您可以在一个调用中使用多个
%s
转换规范。写入
snscanf(src,sizeof(buf1),sizeof(buf2),“%s%s”,buf1,buf2)
毫无意义,尤其是因为它在解析varargs列表时留下了一个无法解决的问题。最好使用
snscanf(src,“%@s%@s”,sizeof(buf1),buf1,sizeof(buf2),buf2)
这样的符号来避免在格式字符串中指定字段大小(减1)。不幸的是,现在使用
sscanf()
等工具无法做到这一点

ISO/IEC 9899:2011(以前)的附录K提供了
sscanf_s()
,它不需要字符串的长度,可以用作:

if (sscanf_s(buffer, "%s %d", string, sizeof(string), &n) != 2)
    ...oops...
(感谢您提醒我这个理论上的选项——理论上是因为只有Microsoft实现了“安全”功能,而他们并没有完全按照标准要求实现这些功能。)

请注意,§K.3.3通用定义
中说:“。。。类型是
rsize\t
,它是
size\t
0.385”类型(脚注385说:'请参见
中RSIZE\u MAX宏的描述',这意味着实际上,只要传递的值在
中的
RSIZE\u MAX
定义的范围内,就可以传递
大小t
。(一般的意图是,
RSIZE_MAX
是一个较大的数字,但小于
SIZE_MAX
。有关更多详细信息,请阅读2011标准,或从网站获取TR 24731。)

有争议的(可选)C11的附录K添加了一个
sscanf_s
函数,该函数采用类型为
rsize_t
的附加参数(也在附录K中定义)在指针参数之后,指定指向数组的大小。无论好坏,这些函数都不受广泛支持。您可以通过将大小放入转换说明符中来实现相同的结果,例如

char out[20];
sscanf(in, "%19s", out);

但是,如果目标对象的大小在运行时可能会发生变化,那么这将非常棘手且容易出错(您必须使用
snprintf
以编程方式构造转换说明符)。请注意,转换说明符中的字段宽度是要读取的最大输入字符数,
sscanf
还为
%s
转换写入终止空字节,因此您传递的字段宽度必须严格小于目标对象的大小。

为什么不尝试
fgets()
(使用标准输入文件
stdin

fgets()
允许您指定缓冲区的最大大小

(在下文中,我将使用标准ISO C99兼容 语法。)

因此,您可以编写以下代码:

#include <stdio.h>
#define MAXBUFF 20 /* Small just for testing... */
int main(void) {
  char buffer[MAXBUFF+1]; /* Add 1 byte since fgets() inserts '\0' at end */
  fgets(buffer, MAXBUFF+1, stdin);
  printf("Your input was: %s\n", buffer);
  return 0;
}
因此,您有一个类似“安全”的方法

注意:此方法存在潜在问题。如果
fgets()
在获取行尾字符“\n”之前到达MAXBUFF字符,则不会丢弃其余输入,并将其作为下一次键盘读取的一部分。
因此,必须添加一个刷新机制,这实际上非常简单:

while(getchar()!'\n') 
    ; /* Flushing stdin... */
但是:如果您只是在
fgets()
行之后添加最后一段代码,
用户每次输入少于MAXBUFF字符时,将被迫按两次ENTER键。最坏情况:这是最典型的情况

要解决此新问题,请注意一个简单的逻辑条件完全等同于未到达字符“\n”的事实,如下所示:

(缓冲区[MAXBUF
if (sscanf_s(buffer, "%s %d", string, sizeof(string), &n) != 2)
    ...oops...
char out[20];
sscanf(in, "%19s", out);
#include <stdio.h>
#define MAXBUFF 20 /* Small just for testing... */
int main(void) {
  char buffer[MAXBUFF+1]; /* Add 1 byte since fgets() inserts '\0' at end */
  fgets(buffer, MAXBUFF+1, stdin);
  printf("Your input was: %s\n", buffer);
  return 0;
}
  char buffer[MAXBUFF+1];
  fgets(buffer, MAXBUFF+1, stdin); /* Plain read */
  int x; float f;
  sscanf(buffer, "%d %g", &x, &f); /* Specialized read */
while(getchar()!'\n') 
    ; /* Flushing stdin... */
fgets(buffer, maxb+1, stdin);
if ((buffer[MAXBUFF - 1] != '\0') && (buffer[MAXBUFF - 1] != '\n'))
     while(getchar() != '\n')
       ;
#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
    char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
    fgets(buffer, maxb+1, stdin); \
    if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
        while(getchar() != '\n') \
           ; \
    sscanf(buffer, fmt, __VA_ARGS__); \
  }
#define MAXBUFF 20     

int main(void) {
  int x; float f;      
  safe_scanf("%d %g", MAXBUFF+1, &x, &f);
  printf("Your input was: x == %d\t\t f == %g",  x, f);
  return 0;
}
char s[2];
s[0]='1'; s[1]='3';
int x;
sscanf(s, "%d", &x);
 snscanf(s, 2, "%d", &x);