What size should I allow for strerror_r?
OpenGroup POSIX.1-2001定义了strerror_r,Linux标准基础核心规范3.1也是如此。但是我找不到错误消息可以合理预期的最大大小的引用。我希望可以在代码中定义一些地方,但是找不到。
该代码必须是线程安全的。这就是为什么使用strerror_r而不使用strerror的原因。
有人知道我可以使用的符号吗?我应该创建自己的吗?
例
1 2 3 4 5 6 7 8 9 10 11 12 13 | int result = gethostname(p_buffy, size_buffy); int errsv = errno; if (result < 0) { char buf[256]; char const * str = strerror_r(errsv, buf, 256); syslog(LOG_ERR, "gethostname failed; errno=%d(%s), buf='%s'", errsv, str, p_buffy); return errsv; } |
来自文档:
开放团体基本规范第6期:
ERRORS
The strerror_r() function may fail if:
- [ERANGE] Insufficient storage was supplied via strerrbuf and buflen to
contain the generated message string.
来源:
glibc-2.7 / glibc-2.7 / string / strerror.c:41:
具有足够大的静态限制可能足以满足所有情况。
如果确实需要获取完整的错误消息,则可以使用GNU版本的strerror_r,也可以使用标准版本。
并使用依次更大的缓冲区对其进行轮询,直到获得所需的内容为止。例如,
您可以使用类似下面的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* Call strerror_r and get the full error message. Allocate memory for the * entire string with malloc. Return string. Caller must free string. * If malloc fails, return NULL. */ char *all_strerror(int n) { char *s; size_t size; size = 1024; s = malloc(size); if (s == NULL) return NULL; while (strerror_r(n, s, size) == -1 && errno == ERANGE) { size *= 2; s = realloc(s, size); if (s == NULL) return NULL; } return s; } int main(int argc, char **argv) { for (int i = 1; i < argc; ++i) { int n = atoi(argv[i]); char *s = all_strerror(n); printf("[%d]: %s\ ", n, s); free(s); } return 0; } |
我不会担心-256的缓冲区大小远远不够,而1024则过大。如果需要存储错误字符串,则可以使用
该程序(在此处在线运行(作为C)):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdio.h> #include <errno.h> #include <string.h> int main(){ const int limit = 5; int unknowns = 0; int maxlen = 0; int i=0; char* s = strerror(i); while(1){ if (maxlen<strlen(s)) maxlen = strlen(s); if (/*BEGINS WITH"Unknown"*/ 0==strncmp("Unknown", s , sizeof("Unknown")-1) ) unknowns++; printf("%.3d\\t%s\ ", i, s); i++; s=strerror(i); if ( limit == unknowns ) break; } printf("Max: %d\ ", maxlen); return 0; } |
列出并打印系统上的所有错误,并跟踪最大长度。从外观上看,该长度不超过49个字符(不带最后一个
我很好奇,是否不能仅通过返回结构来避免整个缓冲区大小协商,以及是否存在不返回结构的根本原因。所以我进行了基准测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #define _POSIX_C_SOURCE 200112L //or else the GNU version of strerror_r gets used #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> typedef struct { char data[64]; } error_str_t; error_str_t strerror_reent(int errn) __attribute__((const)); error_str_t strerror_reent(int errn){ error_str_t ret; strerror_r(errn, ret.data, sizeof(ret)); return ret; } int main(int argc, char** argv){ int reps = atoi(argv[1]); char buf[64]; volatile int errn = 1; for(int i=0; i<reps; i++){ #ifdef VAL error_str_t err = strerror_reent(errn); #else strerror_r(errn, buf, 64); #endif } return 0; } |
,并且-O2两者之间的性能差异很小:
1 2 | gcc -O2 : The VAL version is slower by about 5% g++ -O2 -x c++ : The VAL version is faster by about 1% than the standard version compiled as C++ and by about 4% faster than the standard version compiled as C (surprisingly, even the slower C++ version beats the faster C version by about 3%). |
无论如何,我认为