【问题标题】:Shadowing functions of C stdlib/stdioC stdlib/stdio 的影子函数
【发布时间】:2011-06-16 10:05:33
【问题描述】:

我正在编写一个游戏,现在我可以通过sqlite 使用一个类及其方法来实现一个文件系统。为了让生活更轻松,我计划编写一些函数,如fopenfclosefreadrename 等,以便能够隐藏基本函数并将我的调用定向到我的文件系统而不是原来的。对于前三个函数,这些原型对我来说一切正常:

File *fopen(String _Filename, String _Mode); // i have my own optimized File struct

void fclose(File *_File);

size_t fread(String *_DstBuf, size_t _ElementSize, size_t _Count, File *_File);

这很好用,因为我要么返回另一个结构或参数,除了 File* 而不是 FILE*,但是重命名函数似乎有点棘手!

int rename(String _OldFilename, String _NewFilename);

这几乎是相同的原型。除了我使用std::string(typedef'ed String)而不是const char*!知道如何说服我的编译器使用我的函数或忽略 stdio-one 吗?

【问题讨论】:

    标签: c++ file-io stdio std shadowing


    【解决方案1】:

    您不能简单地以任何其他名称使用您自己的函数的原因是什么?

    如果整个冲突与重载解决方案有关,您应该简单地隐藏 实际 原型;您可以将它们转发给您自己的函数。

    但是,我建议不要在这里采用一般方法:即使有了“修复”,您也最多只能包含排序问题,甚至可能会出现重复的链接符号。

    如果您的函数不这样做,请让它们使用另一个名称。由于您使用的是 c++,因此您可以在 MyFsFunctions.h 中使用这种卑鄙的技巧(否则不明智):

    namespace MyFsFunctions 
    {
         // prototypes for fopen, fclose, fwrite, fread etc
    }
    
    using namespace MyFsFunctions;
    // or:
    using MyFsFunctions::fopen;
    using MyFsFunctions::fclose;
    using MyFsFunctions::fread;
    using MyFsFunctions::fwrite; // etc...
    

    我很确定您仍然希望(需要)隐藏确切的函数原型(或者编译器可能仍然会抱怨不明确的标识符引用)。

    其他提示:

    1. 使用 fuse 文件系统驱动程序(在 Linux/UNIX/MacOS 上;可能有点矫枉过正,但实现它似乎更健壮,甚至可能比您在此处执行的操作更简单)。
    2. 总是有 C 宏(-10 分代表邪恶)
    3. gnu 链接器具有让您“替换”链接符号的选项 - 主要用于调试目的,但您可以在此处利用这些选项

    【讨论】:

    • 卑鄙的命名空间技巧对于第一个原型来说效果很好,但是我遇到了rename 的问题,因为编译器无法确定我的参数是const char* 还是Strings!尝试调用rename(String("/dev/null"), String("/dev/less")); 解决了冲突,但是每次传递参数时调用String 构造函数并不是那么好。
    • 您可以尝试在using namespace MyFsFunctions; 之外/而不是using namespace MyFsFunctions; 之外显式添加using MyFsFunctions::rename; 吗?
    • 没用!但是#define rename MyFsFunctions::rename 可以解决问题,但这是 C++,我不喜欢 C 中的宏。源文件...
    • 我相信你可以在类命名空间中使用。我不确定这是词法范围还是增加了实际的类名称空间。恐怕它是词法范围的,因此如果您在类声明之外有实现,则需要重复它(否则,您可以从 ODR 中受益并从类定义中“自动”使用)。
    • 现在我一定要像这样void foo() { using MyFsFunctions::rename; rename(...); }
    【解决方案2】:

    如何实现一个带有标准签名的rename,它所要做的就是调用您的Stringed 版本?

    对我来说听起来并不复杂。像这样的:

    int rename(const char *charOld, const char *charNew)
    {
        std::string stdOld(charOld);
        std::string stdNew(charNew);
        return rename(stdOld, stdNew);
    }
    

    【讨论】:

    • @littleadv 和@vines - 没用!编译器只是忽略了它!
    • @littleadv - 你能更正你的代码以便我能够复制和粘贴它吗?
    • @littleadv - 我以为你的意思是别的,我已经尝试过这种方式,但完全没有成功! @sehe 使用命名空间的方式似乎是最好的解决方法,但是我必须写一个 prologue 提到我将要使用的所有方法。也许我们可以优化这部分!
    • 如果内联,已经编译好的库代码是看不到的!您必须与要替换的函数具有完全相同相同的签名。
    • @Chris - 使用单独的命名空间确实是一个更好的解决方案,除非您希望将外部库转移到您的代码中,否则您应该使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 2014-04-04
    • 2016-07-28
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多