如何从标准输入获取整数?快速地。可以用准确性换取性能
How to get an integer from stdin? Fast. Can trade accuracy for performance
我正在努力想出一个快速简单的方法
"Get a string from stdin and convert to an integer. If you can't, just pretend we got zero".
这是一个 Linux 嵌入式系统,CPU 和内存非常宝贵。性能很重要,准确性不是那么重要。这应该能够每秒进行多次摄取。我最终会把它变成一个守护进程并将最新的 1024 个值存储在一个数组中。
这是我使用 atoi
的结果:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[] ) {
char *c = argv[1];
unsigned int i = 1; /* on atoi() failure, i = 0 */
if (i = atoi(c)) {
puts ("atoi() success");
}
else {
puts ("atoi() FAILED");
}
printf("argv[1] = %s\n", argv[1]);
printf(" i = %d\n", i);
}
一些测试运行/模糊测试:
# ./test_atoi 3
atoi() success
argv[1] = 3
i = 3
# ./test_atoi 99999999999999999999
atoi() success
argv[1] = 99999999999999999999
i = 2147483647
# ./test_atoi 3.14159
atoi() success
argv[1] = 3.14159
i = 3
# ./test_atoi $(echo -ne "\u2605")
atoi() FAILED
argv[1] = ★
i = 0
这失败了:
# ./test_atoi $(echo -e "[=12=]")
Segmentation fault
然后我会添加一个 NUL 检查:
if (argv[1] == '[=13=]') {
i = 0;
}
这就够了吗?我刚刚(糟糕地)重新实现了 strtol
吗?
我应该继续使用 strtol
吗?如果是,我应该检查什么,strtol
还没有?
我真正关心的不是因为输入错误而死亡。我可以愉快地忍受偶尔从转换中得到垃圾。
编辑:int i = 1
只是因为我想看看 atoi() 是否使它变为 0。
随着时间的推移对贫民窟进行剖析
编辑:我删除了 print 语句并将从 stdin 读取的内容包装到 for 循环中的 atoi/strtol 中。
# time seq 0 999888 | ./test_atoi
real 0m5.245s
user 0m5.870s
sys 0m0.030s
# time seq 0 999888 | ./test_atoi
real 0m5.230s
user 0m5.960s
sys 0m0.050s
# time seq 0 999888 | ./test_atoi
real 0m5.395s
user 0m5.920s
sys 0m0.080s
# time seq 0 999888 | ./test_strtol
real 0m5.332s
user 0m5.860s
sys 0m0.030s
# time seq 0 999888 | ./test_strtol
real 0m5.023s
user 0m5.790s
sys 0m0.060s
# time seq 0 999888 | ./test_strtol
real 0m5.286s
user 0m5.970s
sys 0m0.010s
好吧,这太疯狂了。我应该用我的时间和你的时间做些更有成效的事情!
This is a Linux embedded system, CPU and memory are at a premium.
是的。呃,不。如果你是 运行 一个普通的 linux,你的内核将在几千个地方使用 atoi
和反函数。你的单一数字解析器几乎不会产生任何影响,除非你打算每秒调用它几千次......
Should i just go ahead and use strtol?
出于上述原因:是的。
If yes, anything i should be checking for, that strtol isn't already?
您应该检查 strtol
的 return 值。我真的不同意你的 "don't need precision" 方法。像这样的事情要么做对了,要么就大错特错了。
编辑 你说:
don't need precision = i only care about values 0 - 100
这意味着 a) 您只需要 atoi
,而不是 atol
/strtol
;在那里,节省了 CPU 个周期。接下来您是否真的需要将看起来像 13.288
的字符串转换为整数,或者您是否可以假设所有字符串的长度都是 1 到 3 个字符?在那种情况下,对于原始性能,可能
inline unsigned char char2digit(const char *c) {
unsigned char v = *c - '0';
return (v<1 || v>9)? 0 : v;
}
inline signed char characters2number(const char *string)
{
size_t len = strnlen(string,4);
if(len < 1 || len > 3)
return -1;
signed char val = 0;
signed char power_of_ten = 1;
for(unsigned char idx = 1; idx <= len; ++idx)
{
signed char val += power_of_ten * char2digit(string + len - idx)
power_of_ten *= 10;
}
return val;
}
我的意思是,如果你在烤面包机上。否则 atoi
会支持你。您可能仍想查看 strnlen
.
main (int argc, char **argv)
{
int i = 0;
if (argc > 1)
sscanf (argv [1], "%d", &i);
printf ("i = %d\n", i);
}
我正在努力想出一个快速简单的方法
"Get a string from stdin and convert to an integer. If you can't, just pretend we got zero".
这是一个 Linux 嵌入式系统,CPU 和内存非常宝贵。性能很重要,准确性不是那么重要。这应该能够每秒进行多次摄取。我最终会把它变成一个守护进程并将最新的 1024 个值存储在一个数组中。
这是我使用 atoi
的结果:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[] ) {
char *c = argv[1];
unsigned int i = 1; /* on atoi() failure, i = 0 */
if (i = atoi(c)) {
puts ("atoi() success");
}
else {
puts ("atoi() FAILED");
}
printf("argv[1] = %s\n", argv[1]);
printf(" i = %d\n", i);
}
一些测试运行/模糊测试:
# ./test_atoi 3
atoi() success
argv[1] = 3
i = 3
# ./test_atoi 99999999999999999999
atoi() success
argv[1] = 99999999999999999999
i = 2147483647
# ./test_atoi 3.14159
atoi() success
argv[1] = 3.14159
i = 3
# ./test_atoi $(echo -ne "\u2605")
atoi() FAILED
argv[1] = ★
i = 0
这失败了:
# ./test_atoi $(echo -e "[=12=]")
Segmentation fault
然后我会添加一个 NUL 检查:
if (argv[1] == '[=13=]') {
i = 0;
}
这就够了吗?我刚刚(糟糕地)重新实现了 strtol
吗?
我应该继续使用 strtol
吗?如果是,我应该检查什么,strtol
还没有?
我真正关心的不是因为输入错误而死亡。我可以愉快地忍受偶尔从转换中得到垃圾。
编辑:int i = 1
只是因为我想看看 atoi() 是否使它变为 0。
随着时间的推移对贫民窟进行剖析
编辑:我删除了 print 语句并将从 stdin 读取的内容包装到 for 循环中的 atoi/strtol 中。
# time seq 0 999888 | ./test_atoi
real 0m5.245s
user 0m5.870s
sys 0m0.030s
# time seq 0 999888 | ./test_atoi
real 0m5.230s
user 0m5.960s
sys 0m0.050s
# time seq 0 999888 | ./test_atoi
real 0m5.395s
user 0m5.920s
sys 0m0.080s
# time seq 0 999888 | ./test_strtol
real 0m5.332s
user 0m5.860s
sys 0m0.030s
# time seq 0 999888 | ./test_strtol
real 0m5.023s
user 0m5.790s
sys 0m0.060s
# time seq 0 999888 | ./test_strtol
real 0m5.286s
user 0m5.970s
sys 0m0.010s
好吧,这太疯狂了。我应该用我的时间和你的时间做些更有成效的事情!
This is a Linux embedded system, CPU and memory are at a premium.
是的。呃,不。如果你是 运行 一个普通的 linux,你的内核将在几千个地方使用 atoi
和反函数。你的单一数字解析器几乎不会产生任何影响,除非你打算每秒调用它几千次......
Should i just go ahead and use strtol?
出于上述原因:是的。
If yes, anything i should be checking for, that strtol isn't already?
您应该检查 strtol
的 return 值。我真的不同意你的 "don't need precision" 方法。像这样的事情要么做对了,要么就大错特错了。
编辑 你说:
don't need precision = i only care about values 0 - 100
这意味着 a) 您只需要 atoi
,而不是 atol
/strtol
;在那里,节省了 CPU 个周期。接下来您是否真的需要将看起来像 13.288
的字符串转换为整数,或者您是否可以假设所有字符串的长度都是 1 到 3 个字符?在那种情况下,对于原始性能,可能
inline unsigned char char2digit(const char *c) {
unsigned char v = *c - '0';
return (v<1 || v>9)? 0 : v;
}
inline signed char characters2number(const char *string)
{
size_t len = strnlen(string,4);
if(len < 1 || len > 3)
return -1;
signed char val = 0;
signed char power_of_ten = 1;
for(unsigned char idx = 1; idx <= len; ++idx)
{
signed char val += power_of_ten * char2digit(string + len - idx)
power_of_ten *= 10;
}
return val;
}
我的意思是,如果你在烤面包机上。否则 atoi
会支持你。您可能仍想查看 strnlen
.
main (int argc, char **argv)
{
int i = 0;
if (argc > 1)
sscanf (argv [1], "%d", &i);
printf ("i = %d\n", i);
}