我应该允许strerror_r的大小是多less?

OpenGroup POSIX.1-2001定义了strerror_r ,就像Linux标准核心规范3.1一样 。 但是我找不到可以合理预期的错误信息的最大大小。 我期望有一些定义的地方,我可以把我的代码,但没有我能find。

代码必须是线程安全的。 这就是为什么使用strerror_r而不是strerror的原因。

有没有人知道我可以使用的符号? 我应该创build自己的?


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:

错误

在下列情况下,strerror_r()函数可能失败:

  • [ERANGE]通过strerrbuf和buflen提供的存储空间不足以包含生成的消息string。

来源:

glibc-2.7 /的glibc-2.7 /串/ strerror.c:41:

  char * strerror (errnum) int errnum; { ... buf = malloc (1024); 

Solutions Collecting From Web of "我应该允许strerror_r的大小是多less?"

具有足够大的静态限制对于所有情况可能都足够了。 如果您确实需要获取整个错误消息,则可以使用GNU版本的strerror_r ,也可以使用标准版本,然后使用更大的缓冲区轮询它,直到获得所需的值。 例如,你可以使用类似下面的代码。

 #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", n, s); free(s); } return 0; } 

我不用担心 – 256的缓冲区大小已经足够了,1024是过度的。 您可以使用strerror()而不是strerror_r() ,如果需要存储错误字符串,则可以使用strdup()结果。 虽然这不是线程安全的。 如果你真的需要使用strerror_r()来代替strerror()来保证线程安全,那么只需要使用大小为256.在glibc-2.7 ,最长的错误信息字符串是50个字符(“无效或不完整的多字节或宽字符”)。 我不希望将来的错误信息会更长(在最坏的情况下,会延长几个字节)。

这个程序( 在线运行(如C ++) (顺便说一句,任何人都知道如何编译纯C在线?):

 #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\n", i, s); i++; s=strerror(i); if ( limit == unknowns ) break; } printf("Max: %d\n", maxlen); return 0; } 

列出并打印系统中的所有错误并跟踪最大长度。 从外观上看,长度不超过49个字符(没有最终的\0 ),所以有一些余地,64-100应该足够了。

我很好奇,如果整个缓冲区大小的谈判不能简单地通过返回结构避免,是否有不返回结构的根本原因。 所以我做了基准测试:

 #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上的性能差异很小:

 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%). 

无论如何,我认为strerror甚至被认为是线程不安全的,这是非常奇怪的。 那些返回的字符串应该是指向字符串的指针。 (请赐教,但我不能想到应该在运行时合成的情况)。 而字符串文字是按照定义只读的,只读数据的访问总是线程安全的。