C 中内联声明的困惑
我正在用 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);
因为其中两个(newQueue
和 isEmpty
)非常简单,所以我相信编译器可以用它们做很多好的优化,我决定为它们编写内联声明:
/* 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 风格不同 。我可以传递 -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.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您在标头中定义函数,请使其
静态
。这应该足以让编译器内联它们(inline
只是一个额外的提示)。如果您在整个程序中多次包含该标头,则标头中的非静态函数将导致多个定义。
我做了一些研究并获得了更多信息:
您可以这样使用
inline
。至少在C99中是这样。您只是不能在queue.c
中同时拥有内联和非内联定义。您需要将内联定义包装在#ifdef
中,或将它们移动到queue.c
中未包含的标头。您需要编写两次函数并使用预处理器,但它应该完全按照您想要的方式工作。当函数未内联时,它将仅发出一次。
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 inqueue.c
. You need wrap inline definitions in#ifdef
or 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.
你不应该在queue.c中声明它们
You should not be declaring them in queue.c
在 c99 及更高版本中执行此操作的正确方法是仅在 .c 文件中包含内联函数的外部声明,而不是对其进行定义。这将强制为该函数创建独立代码,以便在由于某种原因无法内联时它将正确链接。请参阅:http://www.greenend.org.uk/rjk/tech/ inline.html
由于函数默认为
extern
这已经足够了:queue.c
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