提问人:kallazz 提问时间:11/11/2023 更新时间:11/12/2023 访问量:112
从 C 中的函数返回静态字符串是一种不好的做法吗?
Is returning a static string from a function in C a bad practice?
问:
我正在开发一个 C 程序,在其中我实现了一个函数来生成用于打印彩色文本的 ANSI 颜色代码。
const char* getAnsiColorCode(int colorId) {
static char colorCode[15];
snprintf(colorCode, sizeof(colorCode), "\e[38;5;%dm", colorId);
return colorCode;
}
我需要做的就是打印一些彩色的hello worlds:
int main(int argc, char *argv[]) {
for (int i = 0; i < 256; i++) {
printf("%sHello, World!\n", getAnsiColorCode(i));
}
}
这是我能找到的最干净的解决方案,但我想知道是否声明,因为没有不好的做法。
每次初始化都会覆盖相同的变量,还是前一个 s 会保留在内存中?我真的不喜欢他们都住在那里的想法。但如果被覆盖,这似乎还不错。colorCode
static
colorCode
colorCode
colorCode
我也尝试了一些其他解决方案,但我不太喜欢它们。
我不想在堆上分配然后释放它。
我也不想把它作为一个论点传递,因为它看起来不那么干净。
有没有比这更好的方法,而且这不是一个坏做法?colorCode
static
static
答:
这种方法的问题在于你有一个隐藏状态,使你的函数在同一个表达式中既不是线程安全的,也不是多重可调用的,包括间接的。static
例如,请考虑以下代码:
int main(int argc, char *argv[]) {
for (int i = 0; i < 256; i++) {
printf("%sHello, World!%s\n", getAnsiColorCode(i), getAnsiColorCode(0));
}
}
输出将是不确定的,因为未指定调用的顺序,但在所有情况下,两个替换输出的 espace 序列都是相同的。getAnsiColorCode
printf
%s
只要静态字符串的值是常量,就可以返回静态字符串,即:在调用之间不会更改。
有 2 种方法可以实现转义序列代码:
在构造序列时使用足够长度的参数数组
char *getAnsiColorCode(char colorCode[static 15], int colorId) { snprintf(colorCode, 15), "\e[38;5;%dm", colorId); return colorCode; } int main(int argc, char *argv[]) { for (int i = 0; i < 256; i++) { char colorCode[15]; printf("%sHello, World!\n", getAnsiColorCode(colorCode, i)); } }
使用静态答案数组(不是完全线程安全的,但可以不受限制地多次调用):
const char *getAnsiColorCode(int colorId) { static char colorCode[256][12]; colorId %= 255; if (!*colorCode[colorId]) { snprintf(colorCode[colorId], sizeof colorCode[colorId], "\e[38;5;%dm", colorId); } return colorCode[colorId]; } int main(int argc, char *argv[]) { for (int i = 0; i < 256; i++) { printf("%sHello, World!\n", getAnsiColorCode(i)); } }
评论
您不需要“辅助函数”,从而消除了使用一个或多个缓冲区的担忧。static
C 语言是一种强大的语言。始终努力利用其设施。
#include <stdio.h>
#define CLR(i,str) "\033[38;5;%dm" str, i
int main( void ) {
for( int i = 0; i < 256; i++ )
printf( CLR( i, "Hello, World! (%d)\n" ), i );
return 0;
}
输出:
Hello, World! (0) // black
Hello, World! (1) // dark red ... use your imagination or give it a try...
Hello, World! (2) // dark green
Hello, World! (3) // ...
Hello, World! (4)
Hello, World! (5)
Hello, World! (6)
Hello, World! (7)
/* ... */
引用彼得·帕克斯(Peter Parkers)的叔叔的话,“权力越大,责任越大。如果处理不当,宏可能会爆炸。警告 emptor。
编辑
或...如果你想让调用文本颜色的代码“看起来更好”,你可以使用 ...VARGS
#include <stdio.h>
#include <stdarg.h>
void printfCLR( int clr, char *fmt, ... ) {
fprintf( stdout, "\033[38;5;%dm", clr ); // output the colour prefix
va_list ap;
va_start( ap, fmt );
vfprintf( stdout, fmt, ap ); // output the string (with arguments)
va_end( ap );
}
int main( void ) {
for( int clr = 0; clr < 256; clr++ )
printfCLR( clr, "Hello, World!\n" ); // 'clean' invocation...
return 0;
}
如果你想看到迷幻的 60 年代的东西......
for( int i = 0; i < 256; i++ ) {
printfCLR( 255-i, "Hello, " );
printfCLR( i, "World!\n" );
}
评论
static
printf
\e
\x1B