【问题标题】:Use a private function in header as #define in c在标头中使用私有函数作为c中的#define
【发布时间】:2021-12-09 16:27:41
【问题描述】:

我有一个函数f,它是:

void f(int x, int y, int z){
    //bla bla bla
}

以及其他一些使用f的函数:

void g(int x, int y, int z){
    f(x, 10, 10); //10, 10 are hard coded
}
void h(int x, int y){
    f(x, y, 20); //20 is hard coded
}

重要提示: f 必须保持私密,并且对其他文件隐藏。

现在,在头文件中,我只是写了hg 的原型。一切正常。

我决定将#define 用于hg,因为它更简单、更标准。所以我把函数去掉了,写在头上:

#define h(x)       f(x, 10, 10)
#define g(x, y)    f(x, y, 10)

问题是,如您所知,我必须在标题中编写f 的原型。 f 必须是私有的。有什么方法可以在这种情况下使用#define 吗?比如使用#def, #undef, ...

注意:随意更改主题

【问题讨论】:

  • 为什么要使用宏。如果有的话,最佳实践建议是尽可能避免使用宏。
  • 宏并不比函数“更标准”。宏并不比函数“具有更高的优先级”。宏是否比函数“容易得多”是值得怀疑的。这个问题是基于错误的前提。要使函数保持私有,请不要在可见的宏中使用它。
  • 考虑使用内联函数而不是宏
  • @MohammadKholghi What's the problem with macros? - 它们有自己的位置,但是因为它们实际上(在 C/C++ 中)告诉预处理器在编译之前进行字符串替换,它们不是类型安全的并且可能导致当事情发生变化时会出现一些非常令人困惑的错误。 Which one do you prefer? - 我绝对更喜欢做同样事情的整个函数,特别是考虑到编译器很可能会在任何调用站点内联它✌️
  • 这是课程的马;当您为嵌入式系统进行开发时,您必须做出不同的权衡。你在程序大小(如果你内联函数会增加)和堆栈大小(如果函数没有内联会增加)方面都受到限制。

标签: c function prototype


【解决方案1】:

我决定为 h & g 使用#define,因为它更简单、更标准。

#define 可能更容易,但实际上并不是更标准。事实上,它容易出错且难以调试。 #define 通常用于更快的处理,因为与函数调用相反,它不使用 RAM(堆栈)或处理时间,因为它只是替换了编译器预处理器。

有了这一点,可以公平地说,当我们希望事情更快地工作时使用#define。

出于您的目的,并且因为您希望 f() 保持私密,您可以通过使用 inline 关键字来实现这一目标,同时让事情变得更快。

static inline void f(int x, int y, int z){
    //bla bla bla
}

inline 关键字指示编译器通常通过#define 中的代码替换来优化对f() 的任何调用。 请注意,内联函数不一定由编译器内联。 有关更多信息,请参阅http://www.greenend.org.uk/rjk/tech/inline.html

虽然您不必将 h & g 创建为函数。你可以这样做:

static inline void f(int x, int y, int z){
    //bla bla bla
}

void fInterface(int x, int y, int z){
    f(x, y, z);
}

然后在头文件中:

void fInterface(int x, int y, int z); // Prototype

#define h(x)       fInterface(x, 10, 10)
#define g(x, y)    fInterface(x, y, 10)

这段代码与导出 f() 本身的性能几乎相同。

希望对您有所帮助!

【讨论】:

  • 我不确定我是否遵循最后一个建议 - 在标题中包含 fInterface 的原型与包含 f 本身的原型有什么区别? (另外,你的代码中有一些不匹配的括号,我认为这只是错误。)
  • 该建议基于问题中的@Mohammad Kholghi 限制。出于某种原因,他希望 f() 是私有的。这可能是因为他使用了别人的代码并且不想更改它。我将纠正不匹配的括号
  • 我认为将 f() 设为私有的目的是为了只能使用某些预定义的值集来调用它。公开一个具有所有相同参数但名称不同的函数并不能实现这一点。
  • 确实,这是其他答案所建议的。
【解决方案2】:

那就不要使用宏了。

这样做:


// header.h
void g(int x, int y, int z);
void h(int x, int y);

// implementation.c
#include "header.h"

static void f(int x, int y, int z){
    //bla bla bla
}

void g(int x, int y, int z){
    f(x, 10, 10); //10, 10 are hard coded
}

void h(int x, int y){
    f(x, y, 20); //20 is hard coded
}

注意在f 上使用static。如果没有将f 声明为static,则无论如何它对程序中的所有其他翻译单元都是可见的。如果你真的想隐藏它,你必须让它成为静态的。

【讨论】:

  • 如果我不使用静态怎么办?别人能有原型吗?
  • 是的。在标头中声明函数或在 .c 文件中声明函数之间没有根本区别。因此,如果您有一个未声明为 static 的函数 f,则在任何 .c 文件中,您可以像 void f(int x,int y,int z); void k(){ f(1,2,3); } 一样声明和使用它
【解决方案3】:

#define 创建一个由编译器替换。宏创建的代码甚至不必是完整的 C 语句,它就像使用宏的人实际键入了扩展版本一样。

因此,如果宏的用户完全键入宏,则宏必须生成有效的代码。您不能在宏中“隐藏”任何内容,因为它必须在编译 C 代码之前进行扩展。

因此,如果您希望函数 f() 是私有的,那么使用 g() 和 h() 函数的原始解决方案是正确的。

【讨论】:

    【解决方案4】:

    你不需要将f的原型写在头文件中。

    secret_data.c:

    static void f(int x, int y, int z){   // F is defined here.
        //bla bla bla
    }
    // Because f is static, it is NOT visible outside this file.
        
    void g(int x, int y, int z){
        f(x, 10, 10); // F is used here
    }
    void h(int x, int y){
        f(x, y, 20); // F is used here
    }
    

    【讨论】:

    • 如果它在源文件中(file.c),那么它是私有的。它不在标题中。将其设为静态究竟是什么意思??
    • @MohammadKholghi: 头文件没什么特别的,在编译时#include 会在包含的地方对头文件内容进行“复制和粘贴”。您可以直接在其中声明函数原型,而不是 #include-ing 标头。
    猜你喜欢
    • 2022-11-24
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 2010-12-11
    • 2013-12-10
    • 1970-01-01
    • 2011-06-30
    • 2011-09-28
    相关资源
    最近更新 更多