执行 fgets 剥离换行的宏
Macro to do fgets stripping newline
给定以下两个语句使用 fgets
并去除换行符:
puts("Enter the name.");
fgets(temp.name, 40, stdin);
temp.name[strcspn(temp.name, "\n")] = 0;
下面的宏是否足以代替这个?
#define FGETS(str, len) fgets(str, len, stdin); str[strcspn(str, "\n")] = 0
FGETS(temp.name, 40);
有什么不足或可以改进的地方吗?
一些备注:
- 当一个宏由多个指令组成时,最好用“do { ... } while(0)”将其括起来,以便能够在没有括号的“if”语句中使用它,防止一些算术运算对宏的操作...
- 宏的参数必须用括号括起来,因为它们可能不是简单的变量而是一些表达式;
- fgets() returns 如果输入 EOF 或出错则为 NULL;
因此有以下命题:
#define FGETS(str, len) do { if (fgets((str), (len), stdin) != NULL) (str)[strcspn((str), "\n")] = 0; else (str)[0] = '[=10=]'; } while(0)
然后您可以将其用作:
if (expression)
FGETS(str, len);
else
do_something_else;
...
FGETS(buf + 34, LEN);
N.B.:这个 page 提供了很多制作安全宏的技巧。
#define READLINE(str, len) do { if(fgets((str), (len), stdin) != NULL) { (str)[strcspn((str), "\n")] = 0; } else { /*TODO: Handle error*/ } } while (0)
注意,我特地从 FGETS
重命名了它,因为它硬编码了 stdin
作为“文件”部分。在我看来,称它为 FGETS
是一种误导。此外,为参数添加了括号 (pretty much a must for macros), wrapped it in a do - while(0)
(here's why) 和处理错误的基本框架。
通常,我会 do { } while (0);
把戏。
但是,如果您想要一个替代 fgets
的宏,您可以在其中透明地测试 return 值,怎么样:
#include <stdio.h>
#include <string.h>
#define FGETS(_buf,_len,_xf) \
({ \
char *_cp = fgets(_buf,_len,_xf); \
if (_cp != NULL) \
_buf[strcspn(_buf,"\n")] = 0; \
_cp; \
})
#define FGETOF(_buf,_xf) \
FGETS(_buf,sizeof(_buf),_xf)
int
main(void)
{
char buf[100];
while (1) {
if (FGETOF(buf,stdin) == NULL)
break;
printf("buf: '%s'\n",buf);
}
return 0;
}
多行宏没问题,但可以使用 inline
函数
清理[速度不受影响]:
#include <stdio.h>
#include <string.h>
static inline char *
xfgets(char *buf,size_t siz,FILE *xf)
{
char *cp;
cp = fgets(buf,siz,xf);
if (cp != NULL)
buf[strcspn(buf,"\n")] = 0;
return cp;
}
#define FGETS(_buf,_len,_xf) \
xfgets(_buf,_len,_xf)
#define FGETOF(_buf,_xf) \
FGETS(_buf,sizeof(_buf),_xf)
int
main(void)
{
char buf[100];
while (1) {
if (FGETOF(buf,stdin) == NULL)
break;
printf("buf: '%s'\n",buf);
}
return 0;
}
文件input/output是时间的后坑。在干净的函数上使用宏几乎没有什么好处。
也许也有做提示的功能?
代码使用每个 C2x priciple 的前导尺寸。
char *getaline(int size, char *s, const char *prompt) {
if (prompt) {
fputs(prompt, stdout);
}
if (fgets(s, size, stdin)) {
// Perhaps add detection of failing to read the whole line?
s[strcspn(s, "\n")] = '[=10=]';
return s;
}
if (size > 0) {
*s = '[=10=]';
}
return NULL;
}
给定以下两个语句使用 fgets
并去除换行符:
puts("Enter the name.");
fgets(temp.name, 40, stdin);
temp.name[strcspn(temp.name, "\n")] = 0;
下面的宏是否足以代替这个?
#define FGETS(str, len) fgets(str, len, stdin); str[strcspn(str, "\n")] = 0
FGETS(temp.name, 40);
有什么不足或可以改进的地方吗?
一些备注:
- 当一个宏由多个指令组成时,最好用“do { ... } while(0)”将其括起来,以便能够在没有括号的“if”语句中使用它,防止一些算术运算对宏的操作...
- 宏的参数必须用括号括起来,因为它们可能不是简单的变量而是一些表达式;
- fgets() returns 如果输入 EOF 或出错则为 NULL;
因此有以下命题:
#define FGETS(str, len) do { if (fgets((str), (len), stdin) != NULL) (str)[strcspn((str), "\n")] = 0; else (str)[0] = '[=10=]'; } while(0)
然后您可以将其用作:
if (expression)
FGETS(str, len);
else
do_something_else;
...
FGETS(buf + 34, LEN);
N.B.:这个 page 提供了很多制作安全宏的技巧。
#define READLINE(str, len) do { if(fgets((str), (len), stdin) != NULL) { (str)[strcspn((str), "\n")] = 0; } else { /*TODO: Handle error*/ } } while (0)
注意,我特地从 FGETS
重命名了它,因为它硬编码了 stdin
作为“文件”部分。在我看来,称它为 FGETS
是一种误导。此外,为参数添加了括号 (pretty much a must for macros), wrapped it in a do - while(0)
(here's why) 和处理错误的基本框架。
通常,我会 do { } while (0);
把戏。
但是,如果您想要一个替代 fgets
的宏,您可以在其中透明地测试 return 值,怎么样:
#include <stdio.h>
#include <string.h>
#define FGETS(_buf,_len,_xf) \
({ \
char *_cp = fgets(_buf,_len,_xf); \
if (_cp != NULL) \
_buf[strcspn(_buf,"\n")] = 0; \
_cp; \
})
#define FGETOF(_buf,_xf) \
FGETS(_buf,sizeof(_buf),_xf)
int
main(void)
{
char buf[100];
while (1) {
if (FGETOF(buf,stdin) == NULL)
break;
printf("buf: '%s'\n",buf);
}
return 0;
}
多行宏没问题,但可以使用 inline
函数
#include <stdio.h>
#include <string.h>
static inline char *
xfgets(char *buf,size_t siz,FILE *xf)
{
char *cp;
cp = fgets(buf,siz,xf);
if (cp != NULL)
buf[strcspn(buf,"\n")] = 0;
return cp;
}
#define FGETS(_buf,_len,_xf) \
xfgets(_buf,_len,_xf)
#define FGETOF(_buf,_xf) \
FGETS(_buf,sizeof(_buf),_xf)
int
main(void)
{
char buf[100];
while (1) {
if (FGETOF(buf,stdin) == NULL)
break;
printf("buf: '%s'\n",buf);
}
return 0;
}
文件input/output是时间的后坑。在干净的函数上使用宏几乎没有什么好处。
也许也有做提示的功能?
代码使用每个 C2x priciple 的前导尺寸。
char *getaline(int size, char *s, const char *prompt) {
if (prompt) {
fputs(prompt, stdout);
}
if (fgets(s, size, stdin)) {
// Perhaps add detection of failing to read the whole line?
s[strcspn(s, "\n")] = '[=10=]';
return s;
}
if (size > 0) {
*s = '[=10=]';
}
return NULL;
}