I'm working on a C program where I've implemented a function to generate ANSI color codes for printing colored text.
const char* getAnsiColorCode(int colorId) {
static char colorCode[15];
snprintf(colorCode, sizeof(colorCode), "\e[38;5;%dm", colorId);
return colorCode;
}
All I need to do for my task is to print some colored hello worlds:
int main(int argc, char *argv[]) {
for (int i = 0; i < 256; i++) {
printf("%sHello, World!\n", getAnsiColorCode(i));
}
}
This is the cleanest solution I could find but I am wondering if declaring colorCode
as static
there is not a bad practice.
Will every initialization of colorCode
override the same variable or will the previous colorCode
s stay in the memory? I don't really like the idea of all of them staying there. But if colorCode
gets overwritten it doesn't seem bad.
I also tried some other solutions, but I don't like them as much.
I don't want to allocate colorCode
on the heap and then free it.
I also don't want to pass it as an argument, because it looks less clean that way.
Is there a better way of doing it than static
and is static
here not a bad practice?
The problem with this approach is you have a hidden static
state that makes your function neither thread safe not multi callable in the same expression, including indirectly.
Consider for example this code:
int main(int argc, char *argv[]) {
for (int i = 0; i < 256; i++) {
printf("%sHello, World!%s\n", getAnsiColorCode(i), getAnsiColorCode(0));
}
}
The output will be indeterminate as the order of calls for the getAnsiColorCode
is unspecified, but in all cases the espace sequence output by printf
will be the same for both %s
replacements.
It is OK to return a static string as long as its value is constant, ie: does not change across calls.
There are 2 ways to achieve your escape sequence code:
using an argument array of sufficient length where the sequence is constructed
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));
}
}
Using a static array of answers (not fully thread safe, but callable multiple times without restrictions):
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));
}
}