Printf/scanf替代方法:需要一些反馈/建议

3
我最近写了一些基本的命令行程序(我想保持我的技能在暑假期间),但是printfscanf开始让我感到烦恼。我不是一个出色的C程序员,必须使用printf/scanf及其不稳定性(甚至更糟糕的是fgets等)并不能让我感到舒适(正因为如此,我喜欢NSLog,它具有安慰人心的默认命名空间以及自动的NSStringNSObject解析)。
然而,令我非常失望的是,NSLog没有对应的函数,并且打印了很多额外的“垃圾”(时间、函数名称等,以及结尾处的换行符),这使得我使用它的目的大大降低了。因此,我决定坐下来进行另一种类型的编程练习,编写函数来替换printf和scanf,以满足我的需求。
我自己创建了一个名为NSInput.h的文件,其中包含两个函数:NSPrint()NSScan()。这两个函数的模型类似于printf和scanf,但也处理NSString。我知道我在这里涉足了神圣的命名空间,但我无法抵制(IFPrintIFScan听起来太糟糕了!)。
现在,虽然我很高兴我有工作代码(您可以在此处找到源代码),但我知道它不够高效(尽管令我惊讶的是,在Xcode 4的LLDB下,NSPrintprintf快几倍,但这不是重点)。我需要一些关于如何使函数更好、更高效的建议。例如,NSScan将其收到的va_list转换为NSPointerArray,并使用NSScanner扫描格式和输入字符串,所以我知道还有很大的改进空间。
基本上,我想知道的是,我有没有犯任何明显的错误需要修正?我是否遗漏了什么重要的东西?我应该被称为被宠坏的孩子,回到使用printf和scanf吗?请告诉我,我在寻求意见(双关语不是故意的!)...
提前感谢!

你在 printf 类似的函数中寻找什么,而使用 [NSString stringWithFormat:] 无法得到? - Seamus Campbell
2
我注意到的一个明显的遗漏是缺乏测试套件。 - Greg Hewgill
1
@Seamus:如果你看源码,那正是我所做的。 @Greg:实际上我以前从未做过测试套件,所以我想现在试一下也是个好时机,对吧?感谢回复! - Itai Ferber
糟糕,我的大脑一直在想sprintf,我一直在试图弄清楚为什么你要重新发明轮子,而只是作为现有轮子的一个薄包装。 :) - Seamus Campbell
1
不要称它们为NSPrint和NSScan。不,绝对不要! - JeremyP
1个回答

3

我的想法:

  • 不要称呼它们为NSxxxxx,NS是保留给Cocoa和Foundation的。
  • 两个函数都应该修改为接受FILE*,即您应该为更灵活性建模fprintf()fscanf()的接口。
  • 如果您使用fputs(),则您的printf函数可能会更好。

例如:

void NSFPrint (FILE* fp, NSString *format, ...) 
{
    // Create the variable argument list.
    va_list args;
    va_start(args, format);

    // Using NSString, parse the argument list and convert it to a C string.
    fputs([[[[NSString alloc] initWithFormat:format arguments:args] autorelease] UTF8String], fp);
     va_end(args);
}
  • 请考虑添加对除UTF-8之外编码的输入和输出支持。
  • 您的 scanf 替代品在标准输入上混合使用了 C 缓冲 IO 和 Unix 未缓冲 IO。这可能不太好。
  • 您的 scanf 替代品即使不需要也会读取到行末。我没有详细检查过,但如果扫描格式没有消耗整行,则看起来您正在丢弃输入。这可能不太好。

谢谢您的建议!我会尽快实施它们。只有一个问题,您说的同时使用C缓冲IO和Unix非缓冲IO是什么意思?或者说,我该如何避免这个问题? - Itai Ferber
我稍微更新了一下我的代码(http://snipt.org/XmL),以反映您的建议(我已经重命名了`IFPrint`和`IFScan`函数,它们现在以文件指针作为参数,`IFPrint`现在使用`fputs`,并且我用`fgetc`替换了`read(0, NULL, 1)`——这就是你所说的缓冲/非缓冲IO吗?)希望我朝着正确的方向前进。 - Itai Ferber
2
是的。read()函数调用是一个Unix系统调用,它使用仅Unix IO调用直接从文件描述符读取。fgets()是一个操作FILE*文件指针的C库函数。文件指针维护一个缓冲区,当这个缓冲区耗尽时,fgets只从物理文件中读取。而且,当它读取时,它会读取一个大块。这样,做fgetc()并不像你想象的那么低效,因为大多数时间它从内部缓冲区获取字符。 - JeremyP
现在,这个怎么样:http://pastie.org/1081717?我意识到如果我将来需要使用`IFPrint`写入文件,我更可能使用`NSFileHandle`而不是`FILE *,所以我相应地进行了修改。IFPrint将保持与以前相同的高效代码(打印到stdout),而IFFPrint将使用NSFileHandle打印。我以同样的方式拆分了IFScan,让用户通过给定的偏移量扫描NSFileHandle`。你认为这值得花费精力吗,还是我在浪费时间? - Itai Ferber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接