关于C中内联声明的困惑

时间:2011-10-18 20:03:46

标签: c gcc inline c99 clang

我在C中实现队列的实现。我的界面包含五个访问队列的简单函数:

#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);

由于其中两个(newQueueisEmpty)非常简单,我相信编译器可以对它们做很多好的优化,我决定为它们编写内联声明:

/* 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;
}

使用gcc进行编译。但是当我用clang编译它时,它给了我一个错误。一项快速研究表明,从GNU风格中进行这些内联声明is different的官方方式。我可以传递-std=gnu89或根据上面的链接更改功能签名。我选择了第二个选项:

inline queue newQueue(void) {
  queue q = { NULL, NULL };
  return q;
}

inline bool isEmpty(queue q) {
  return q.first == NULL;
}

但是现在,当以c99模式编译时,clang和gcc都会说一些关于重复函数声明的内容。这是queue.c中的附带定义:

#include "queue.h"

/* ... */

queue newQueue() {
  queue q = { NULL, NULL };
  return q;
}

bool isEmpty(queue q) {
  return q.first == NULL;
}

我做错了什么?如何在不需要切换到gnu89模式的情况下获得我想要的内容?

这些是我用第二种风格得到的错误信息:

$ 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.

3 个答案:

答案 0 :(得分:5)

如果要在标题中定义函数,请将它们static。这应该足以让编译器内联它们(inline只是一个额外的提示)。

如果在整个程序中多次包含该标题,

标题中的非static函数将导致多个定义。

我做了一些研究并获得了更多信息:

您可以这样使用inline。至少在C99。您只能在queue.c中同时拥有内联和非内联定义。您需要在#ifdef中包含内联定义,或将其移至queue.c中未包含的标题。

您需要编写两次函数并使用预处理器,但它应该完全按照您的意愿工作。当函数没有内联时,它只会发出一次。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

在c99及更高版本中执行此操作的正确方法是仅在.c文件中具有内联函数的外部声明,而不是其定义。这将强制为该函数创建独立代码,以便在由于某种原因无法进行内联时它将正确链接。请参阅:http://www.greenend.org.uk/rjk/tech/inline.html

由于函数默认为extern,这就足够了:

queue.c

#include "queue.h"

/* ... */

queue newQueue();

bool isEmpty(queue q);