如何使用#defined 常量作为 fscanf 中的最大字段宽度?
How do I use a #defined constant as the max field width in fscanf?
所有这些都是在 C89 中,而不是 C99。
我有一个常数。
#define MAX_NAME_LEN 256
我想将它用作 fscanf 中的最大字段宽度,有点像这样。
fscanf(input, "%256s", name);
但我想使用 MAX_NAME_LEN 而不是文字 256 以保持良好的风格。我已经尝试了所有
fscanf(input, "%MAX_NAME_LENs", name);
char* max_name_len_str = malloc(16 * sizeof *max_name_len_str);
sprintf(max_name_len_str, "%d", MAX_NAME_LEN);
fscanf(input, "%" max_name_len_str "s", name);
free(max_name_len_str);
//works with printf, but has different meaning in scanf
fscanf(input, "%*s", MAX_NAME_LEN, name);
fscanf(input, "%%ds", MAX_NAME_LEN, name);
没有成功。
char* nameFormat = malloc(16 * sizeof *nameFormat); //I assume I don't ever want more than 10^13 characters in a name
sprintf(nameFormat, "%s%ds", "%", MAX_NAME_LEN);
fscanf(input, nameFormat, name);
free(nameFormat);
确实有效,但是当所有人都出去的时候很笨拙。有没有更优雅的解决方案?
你可以使用这个宏:
#define STRINGIFY(X) INDIRECT(X)
#define INDIRECT(X) #X
像这样:
#define MAX 10
puts("%"STRINGIFY(MAX)"d");
这将打印 %10d
.
你的情况是
char name[MAX_NAME_LEN + 1];
fscanf(input, "%"STRINGIFY(MAX_NAME_LEN)"s", name);
宏中的 #
字符串化(使 "
围绕它)后面的任何内容。所以宏只能是十进制数。
需要间接级别才能将 MAX_NAME_LEN
扩展到 256
。 INDIRECT(MAX_NAME_LEN)
将扩展为 "MAX_NAME_LEN"
。
您将与 fscanf 斗争。如果您与 fscanf 绑定,我不知道比您提出的更好的解决方案。
就我个人而言,我会像这个简单的例子一样切换到 fgets:
#define MAX_NAME_LEN 25
int main()
{
char string[MAX_NAME_LEN];
fgets(string,MAX_NAME_LEN,stdin);
printf("%s", string);
}
第一次简化。
// Unlikely need to malloc short array
char nameFormat[16]; // I assume I don't ever want more than 10^13 characters
sprintf(nameFormat, "%%%ds", MAX_NAME_LEN); // %% prints a %
fscanf(input, nameFormat, name);
第二次提供或更好,使用 stringify 。
请注意,缓冲区的大小至少需要比 "%s"
宽度大 1。
#define MAX_NAME_LEN 256
#define MAX_NAME_LEN_STR "256"
char name[MAX_NAME_LEN + 1];
fscanf(input, "%" MAX_NAME_LEN_STR "s", name);
3,使用fgets()
(我的偏好),当然这会读取行而不是一系列非白色-space字符。不过,这通常确实可以实现更高级别的目标。
#define MAX_NAME_LEN 256
char name[MAX_NAME_LEN + 2];
fgets(name, sizeof name, input);
作为参考,以下是 fscanf_s()
未达到 C99 合规性的 VS 早期版本所使用的防止溢出的方法。 unsigned
参数跟在 name[]
指示缓冲区大小之后。这似乎也适用于 VS 2015。
char name[MAX_NAME_LEN + 1];
fscanf_s(input, "%s", name, (unsigned) sizeof name);
C11 在其附件 K 中包含 fscanf_s()
,它是 规范的 ,仅供参考,因此兼容的编译器不需要实现它。然而在 C11 中,它被指定为需要一个 rsize_t/size_t
参数 .
fscanf_s(input, "%s", name, sizeof name);
如果输入超过256个非白色-space字符,匹配失败。在这种情况下,fscanf()
return EOF
。我认为 VS 版本也是如此。我认为两者都会消耗流中的所有非白色-space,即使没有足够的空间来存储它们。
其中任何一个都与下面的有点不同,因为额外的文本不会读入 name[]
,所以没有缓冲区溢出。任何额外的文本都保留用于下一个输入函数调用。 fscanf()
returns 1.
fscanf(input, "%256s", name);
所有这些都是在 C89 中,而不是 C99。
我有一个常数。
#define MAX_NAME_LEN 256
我想将它用作 fscanf 中的最大字段宽度,有点像这样。
fscanf(input, "%256s", name);
但我想使用 MAX_NAME_LEN 而不是文字 256 以保持良好的风格。我已经尝试了所有
fscanf(input, "%MAX_NAME_LENs", name);
char* max_name_len_str = malloc(16 * sizeof *max_name_len_str);
sprintf(max_name_len_str, "%d", MAX_NAME_LEN);
fscanf(input, "%" max_name_len_str "s", name);
free(max_name_len_str);
//works with printf, but has different meaning in scanf
fscanf(input, "%*s", MAX_NAME_LEN, name);
fscanf(input, "%%ds", MAX_NAME_LEN, name);
没有成功。
char* nameFormat = malloc(16 * sizeof *nameFormat); //I assume I don't ever want more than 10^13 characters in a name
sprintf(nameFormat, "%s%ds", "%", MAX_NAME_LEN);
fscanf(input, nameFormat, name);
free(nameFormat);
确实有效,但是当所有人都出去的时候很笨拙。有没有更优雅的解决方案?
你可以使用这个宏:
#define STRINGIFY(X) INDIRECT(X)
#define INDIRECT(X) #X
像这样:
#define MAX 10
puts("%"STRINGIFY(MAX)"d");
这将打印 %10d
.
你的情况是
char name[MAX_NAME_LEN + 1];
fscanf(input, "%"STRINGIFY(MAX_NAME_LEN)"s", name);
宏中的 #
字符串化(使 "
围绕它)后面的任何内容。所以宏只能是十进制数。
需要间接级别才能将 MAX_NAME_LEN
扩展到 256
。 INDIRECT(MAX_NAME_LEN)
将扩展为 "MAX_NAME_LEN"
。
您将与 fscanf 斗争。如果您与 fscanf 绑定,我不知道比您提出的更好的解决方案。
就我个人而言,我会像这个简单的例子一样切换到 fgets:
#define MAX_NAME_LEN 25
int main()
{
char string[MAX_NAME_LEN];
fgets(string,MAX_NAME_LEN,stdin);
printf("%s", string);
}
第一次简化。
// Unlikely need to malloc short array
char nameFormat[16]; // I assume I don't ever want more than 10^13 characters
sprintf(nameFormat, "%%%ds", MAX_NAME_LEN); // %% prints a %
fscanf(input, nameFormat, name);
第二次提供或更好,使用 stringify
请注意,缓冲区的大小至少需要比 "%s"
宽度大 1。
#define MAX_NAME_LEN 256
#define MAX_NAME_LEN_STR "256"
char name[MAX_NAME_LEN + 1];
fscanf(input, "%" MAX_NAME_LEN_STR "s", name);
3,使用fgets()
(我的偏好),当然这会读取行而不是一系列非白色-space字符。不过,这通常确实可以实现更高级别的目标。
#define MAX_NAME_LEN 256
char name[MAX_NAME_LEN + 2];
fgets(name, sizeof name, input);
作为参考,以下是 fscanf_s()
未达到 C99 合规性的 VS 早期版本所使用的防止溢出的方法。 unsigned
参数跟在 name[]
指示缓冲区大小之后。这似乎也适用于 VS 2015。
char name[MAX_NAME_LEN + 1];
fscanf_s(input, "%s", name, (unsigned) sizeof name);
C11 在其附件 K 中包含 fscanf_s()
,它是 规范的 ,仅供参考,因此兼容的编译器不需要实现它。然而在 C11 中,它被指定为需要一个 rsize_t/size_t
参数 .
fscanf_s(input, "%s", name, sizeof name);
如果输入超过256个非白色-space字符,匹配失败。在这种情况下,fscanf()
return EOF
。我认为 VS 版本也是如此。我认为两者都会消耗流中的所有非白色-space,即使没有足够的空间来存储它们。
其中任何一个都与下面的有点不同,因为额外的文本不会读入 name[]
,所以没有缓冲区溢出。任何额外的文本都保留用于下一个输入函数调用。 fscanf()
returns 1.
fscanf(input, "%256s", name);