I am implementing an implementation of queues in C. My interface consists of five simple function to access the queue:
#ifndef QUEUE_H
#define QUEUE_H
#include <stdbool.h>
#include <stddef.h>
struct queue {
struct cell* first;
struct cell* last;
};
typedef struct queue queue;
extern queue newQueue(void);
extern bool isEmpty(queue);
extern queue enqueue(queue,void*);
extern queue dequeue(queue);
extern void* front(queue);
extern void freeQueue(queue);
Since two of them (newQueue and isEmpty) are so trivial that I believe that a compiler can do many good optimizations with them, I decided to write inline declarations for them:
/* replacing the two lines
extern queue newQueue(void);
extern bool isEmpty(queue);
in the original header */
extern inline queue newQueue(void) {
queue q = { NULL, NULL };
return q;
}
extern inline bool isEmpty(queue q) {
return q.first == NULL;
}
This compile fine with gcc. But when I compile it with clang, it gives me an error. A quick research shows, that the official way of doing these inline declarations is different from the GNU style. I could either pass -std=gnu89 or change the function signatures according to the link above. I chosed the second option:
inline queue newQueue(void) {
queue q = { NULL, NULL };
return q;
}
inline bool isEmpty(queue q) {
return q.first == NULL;
}
But now, both clang and gcc say something about duplicate function declarations, when compiled in c99 mode. This is the accompanying definition in queue.c:
#include "queue.h"
/* ... */
queue newQueue() {
queue q = { NULL, NULL };
return q;
}
bool isEmpty(queue q) {
return q.first == NULL;
}
What am I doing wrong? How can I get what I want without needing to switch into gnu89 mode?
These are the error messages I get with the second style:
$ gcc -std=c99 queue.c
queue.c:12:7: error: redefinition of ‘newQueue’
queue.h:14:21: note: previous definition of ‘newQueue’ was here
queue.c:17:6: error: redefinition of ‘isEmpty’
queue.h:19:20: note: previous definition of ‘isEmpty’ was here
$ clang -std=c99 queue.c
queue.c:12:7: error: redefinition of 'newQueue'
queue newQueue() {
^
In file included from queue.c:5:
./queue.h:14:21: note: previous definition is here
extern inline queue newQueue(void) {
^
queue.c:17:6: error: redefinition of 'isEmpty'
bool isEmpty(queue q) {
^
In file included from queue.c:5:
./queue.h:19:20: note: previous definition is here
extern inline bool isEmpty(queue q) {
^
2 errors generated.
If you are defining functions in headers make them
static. This should be enough for compiler to inline them (inlineis just an additional hint).Non
staticfunctions in headers will result in multiple definitions, if you include that header more than one time in your whole program.I have done some research and have more info:
You can use
inlinethat way. At least in C99. You just cannot have both inline and non-inline definitions inqueue.c. You need wrap inline definitions in#ifdefor move them to header not included inqueue.c.You need to write the functions twice and play with the preprocessor, but it should work exactly as you want. When function is not inlined, it will be emitted only once.