在C中,使用标准库或编写自己的函数会更快吗?

时间:2010-07-13 01:26:37

标签: c optimization performance

例如,<ctype.h>中有isalpha()等函数。

我想知道自己编写isalpha函数是否比调用isalpha更快?


感谢您的所有即时回复!只是想让我的问题更清楚:

所以即使是isalpha功能?因为你可以简单地传递一个角色并检查角色是否在'a'和'z'||之间'A'和'Z'?

另一个问题:当你包含一个像ctype.h这样的std库并只调用一个像isalpha这样的函数时,是否会加载文件(我的意思是所有代码行)?我担心的是,大尺寸会使程序变慢

10 个答案:

答案 0 :(得分:65)

除非您有特定的理由这样做(例如,您有特定的要求不使用标准库,或者您已经描述了一个非常具体的用例,您可以编写一个性能更好的函数),您应该总是喜欢使用标准库函数,而不是编写自己的函数。

标准库函数经过大量优化并经过了充分测试。此外,编译器附带的标准库可以利用编译器内在函数和您在自己的代码中无法使用的其他低级细节。

答案 1 :(得分:14)

isalpha不只是检查其参数是否在A-Za-z范围内。引用C标准(第7.4.1.2节):

  

isalpha功能测试任何   isupper或islower的字符   是真的,或任何一个角色   特定于语言环境的字母集   字符,其中没有iscntrl,   isdigit,ispunct或isspace是真的。

很可能你可以编写一个更有限的版本(正如你的建议),它对于它处理的案例子集更快,但它不是isalpha函数。库程序不仅存在效率,而且完整和正确。效率实际上是最容易的部分;让所有边缘情况正确是努力工作的地方。


另请注意,如果您要编写一个针对英语/ ASCII的优化版本,您可以使用其他人建议的查找表或我个人的偏好(< em>编辑以修复R抓住的错误。)

int isalpha(int c) {
    return ((unsigned int)(c | 32) - 97) < 26U;
}

答案 2 :(得分:8)

通常,您应该尽可能使用C库。一个真正的原因不是当你在嵌入式环境中而且空间有限时(通常情况并非如此,几乎所有嵌入式平台都为平台提供了C库)。

一个例子可能是使用isalpha函数实际上可能会拖入包含所有is...函数的目标文件,而您不需要其中任何一个(目标文件是典型的最小值)链接时的单位虽然一些链接器可以归结为单个函数。)

通过编写自己的isalpha,您可以确保将其(仅限于它)合并到最终的二进制文件中。

在某些有限的情况下,您可能会获得更快的速度,而您可能需要执行非常具体的操作,并且库正在处理更常见的情况。同样,只有在特定循环是系统中的瓶颈时才需要。您可能还希望选择与库编写者所选择的速度/空间权衡不同的速度/空间权衡,一个例子正在改变:

int isalpha (int c) {
    return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
}

成:

int isalpha (int c) {
    static int map[256] = {0,0,0,0,...,1,1,1,...,0,0,0};
    return map[c & 0xff];
}

(可能)更快的实现,代价是地图的额外存储(并且您需要了解您的执行环境,因为它不可移植)。

不使用它们的另一个原因是提供一种更安全的方式来处理诸如字符串之类的东西,其中安全性/健壮性是 CRITICAL 因素。这通常会花费你更多的时间来证明正确性。

答案 3 :(得分:6)

标准库函数是由非常聪明的人编写的,并且已经过彻底的审查,调试和优化。在每个可以想象的生产环境中,它们都经过了数百万次的测试。很有可能你的自定义功能不会更好或更快。

答案 4 :(得分:6)

这里已经有了很多答案,但除了斯蒂芬·佳能之外没有一个解决了最重要的部分:不同的语义。这是选择使用哪些功能的最重要因素。

标准C库isalpha等函数被指定为根据当前语言环境工作。如果将语言环境保留为默认的"C"语言环境(未能调用setlocale),则它们具有非常可预测的行为,但这排除了使用应用程序的唯一标准化方法来检测和使用系统的/用户首选的字符编码,数字格式,消息语言和其他本地化首选项。

另一方面,如果你实现自己的isalpha(最佳实现是((unsigned)c|32)-'a'<26,或者如果你喜欢更自我记录的代码,((unsigned)c|('A'^'a')-'a'<='z'-'a'),它总是非常无论语言环境如何,都可预测的行为。

我甚至会将认为有害的附加到使用标准isalpha等功能,除了假定用户的语言环境格式的文本的天真文本处理之外的任何内容。这些函数特别不适合解析配置文件,基于文本的网络事务,HTML,编程语言源等。(一个例外是isdigit,ISO C要求它等同于return (unsigned)c-'0'<10;。)On另一方面,如果您正在编写具有高级自然语言文本处理功能的应用程序(如文字处理程序或Web浏览器),那么它需要具有比C库所能提供的更高级的字符属性处理,您应该是寻找一个好的Unicode库。

答案 5 :(得分:2)

虽然如果你仔细写它,它很可能不会慢一些,但我几乎可以保证你不会做出比现有更优化的东西。我能想到的唯一一个案例就是它是一个函数而你是反复内联的 - 但是如果它是一个宏,你就不会打败它。使用标准。

答案 6 :(得分:1)

在许多C / C ++环境(例如VisualC)中,可以使用“C运行时库”(CRT)的源代码。查看函数CRT中的代码,然后尝试思考“你能做得更好吗?”。

答案 7 :(得分:1)

我唯一没有在标准库中使用某些东西的地方就是缺少某些东西,除非打开该库的特定扩展名。

例如,要在GNU C中获取asprintf(),您需要在包含_GNU_SOURCE之前启用<stdio.h>。甚至在strdup()<string.h>被{{1}}击中或遗漏的时间。

如果我严重依赖这些扩展,那么我会尝试将它们包含在我的代码库中,以便我不必编写kludges来解决它们的缺席。

然后有一些罕见的例子,你想要以更好的方式推出自己的版本,例如,默认情况下提供POSIX行为(或其他东西)。

除此之外,自己实施stdc的东西似乎有点傻,超出了良好的学习练习的价值。

答案 8 :(得分:1)

有趣的是,你问题中isalpha()的实现比30年前C库提供的最常见的实现要慢。请记住,这是一个将在普通C编译器的关键内循环中使用的函数。 :)

我承认当前的库实现可能比以前慢一些,因为我们今天必须解决字符集问题。

答案 9 :(得分:0)

几行或一行C代码不一定能转化为最简单,最快速的解决方案。 memcpy of while( - len)* d ++ = * s ++;绝对是最慢的。这些库通常做得很好而且速度很快,你可能很难改进它们。您可能会看到获益的地方是在特定平台上,您可以在这些平台上了解编译器所没有的平台。例如,目标可能是32位处理器,但您可能知道64位对齐访问更快,并且可能希望修改库以利用该特殊情况。但总的来说,对于所有目标的所有平台,您可能都不会做得更好,已针对热门目标编写了针对特定的优化,并且在热门编译器的C库中。