C 中内联声明的困惑

发布于 2024-12-10 21:45:54 字数 2281 浏览 0 评论 0原文

我正在用 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 风格不同 。我可以传递 -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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谈场末日恋爱 2024-12-17 21:45:54

如果您在标头中定义函数,请使其静态。这应该足以让编译器内联它们(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 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.

帅哥哥的热头脑 2024-12-17 21:45:54

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

You should not be declaring them in queue.c

咋地 2024-12-17 21:45:54

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

由于函数默认为 extern 这已经足够了:

queue.c

#include "queue.h"

/* ... */

queue newQueue();

bool isEmpty(queue q);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文