简体   繁体   中英

Confusion about inline declarations in C

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 ( inline is just an additional hint).

Non static functions 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 inline that way. At least in C99. You just cannot have both inline and non-inline definitions in queue.c . You need wrap inline definitions in #ifdef or move them to header not included in queue.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.

The proper way of doing this in c99 and onward is to merely have an external declaration of an inline function in the .c file instead of a definition of it. This will force standalone code to be created for that function so that it will link properly if inlining is not possible for some reason. See: http://www.greenend.org.uk/rjk/tech/inline.html

Since functions default to extern this is sufficient:

queue.c

#include "queue.h"

/* ... */

queue newQueue();

bool isEmpty(queue q);

你不应该在queue.c中声明它们

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM