C extern keyword correct use

115 Views Asked by At

I'm writing a simple library to colorize the terminal's text, but maybe i'm doing it wrong.

colors.h:

extern enum col;
extern char* colors[8];
extern char* bold_colors[8];

void printColor(char* color, char* str);

colors.c:

#include <stdio.h>
#include <string.h>
#include <colors.h>

enum col {
    BLACK, RED, GREEN, BLUE, YELLOW, PURPLE, CYAN, WHITE, MAX_VALUE
};

char* colors[8] = {
    [BLACK] = "\033[0;30m",
    [RED] = "\033[0;31m",
    [GREEN] = "\033[0;32m",
    [YELLOW] = "\033[0;33m",
    [BLUE] = "\033[0;34m",
    [PURPLE] = "\033[0;35m",
    [CYAN] = "\033[0;36m",
    [WHITE] = "\033[0;37m"
};

char* bold_colors[8] = {
    [BLACK] = "\033[1;30m",
    [RED] = "\033[1;31m",
    [GREEN] = "\033[1;32m",
    [YELLOW] = "\033[1;33m",
    [BLUE] = "\033[1;34m",
    [PURPLE] = "\033[1;35m",
    [CYAN] = "\033[1;36m",
    [WHITE] = "\033[1;37m"
};

void printColor(char* color, char* str) {
    printf("\033[0;37m");
    printf(color);
    printf(str);
    printf("\033[0;37m");
}

main.c

#include "colors.h"

printColor(colors[GREEN], "text");

The error: identifier "GREEN" is undefinedC/C++(20)

it should share the colors arrays across the files (multiple) but returns an error.

3

There are 3 best solutions below

4
anatolyg On BEST ANSWER

You probably want to move your enum to a header file and include that in both colors.c and main.c

– Allan Wind

I agree with this.

Programming in C includes compilation and linkage.

At compilation stage, declarations in h-files have effect in c-files, but c-files don't affect each other. Your problem happens here. You fix it by placing all used declarations in your h-file.

At linkage stage, compiled c-files are linked together. Your extern declarations take effect here. However, they are needed in the compilation stage too, so it's correct to put them in h-files.

0
Lundin On

Not sure how you managed to get this to compile cleanly, because a forward declaration extern enum col; of an enum isn't valid C.

C17 6.7.2.3:

Constraints
...
A type specifier of the form
enum identifier
without an enumerator list shall only appear after the type it specifies is complete.

This is not the case in your current header file. So you need to move the enum declaration to that header file, or it won't be visible to other translation units. I recommend always using it together with typedef:

// colors.h
typedef enum {
    BLACK, RED, GREEN, BLUE, YELLOW, PURPLE, CYAN, WHITE, MAX_VALUE
} col;

As noted in comments, custom header files should always be included with #include "colors.h".

0
Adrian Charles On

Usually we put definitions of data types, structs, and enumeration types in header files, like your enum col, you should put it into your header file. Then if you want use these data types or structs to define some data entities, you just need to include that header file.

As for the arrays like colors、 bold_colors, where the actual data is stored, should be put into the source file.

As we can see, you define the arrays colors、 bold_colors as global variables in color.c, if you want to use them just in color.c, other module should not see these global variables, then extern is not recommended. On the contrary, if you need a shared global variable(like you use it in main.c), you can use extern in color.c or other source file, then you can visit it in that source file. It works, but, we prefer a safer way: define a global variable in a source file, declare an interface in header file, and implement it in source file, and use this interface to get or set the global variable you defined in source file.