将调用者 __FILE__ __LINE__ 传递给函数而不使用宏

发布于 2024-10-02 23:25:32 字数 416 浏览 2 评论 0原文

我已经习惯了:

class Db {
  _Commit(char *file, int line) {
    Log("Commit called from %s:%d", file, line);
  }
};

#define Commit() _Commit(__FILE__, __LINE__)

但最大的问题是我在全局范围内重新定义了“Commit”这个词,而在 400k 行的应用程序框架中这是一个问题。我不想使用像 DbCommit 这样的特定单词:我不喜欢像 db->DbCommit() 这样的冗余,或者在任何地方手动传递值:db->Commit(__FILE__, __LINE__) 是最糟糕的。

那么,有什么建议吗?

I'm used to this:

class Db {
  _Commit(char *file, int line) {
    Log("Commit called from %s:%d", file, line);
  }
};

#define Commit() _Commit(__FILE__, __LINE__)

but the big problem is that I redefine the word Commit globally, and in a 400k lines application framework it's a problem. And I don't want to use a specific word like DbCommit: I dislike redundancies like db->DbCommit(), or to pass the values manually everywhere: db->Commit(__FILE__, __LINE__) is worst.

So, any advice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(3

半衾梦 2024-10-09 23:25:32

因此,您希望使用文件和文件进行日志记录(或其他操作)。行信息,您宁愿不使用宏,对吧?

归根结底,这根本无法用 C++ 完成。无论您选择什么机制 - 无论是内联函数、模板、默认参数还是其他东西 - 如果您不使用宏,您最终都会得到文件名和文件名。日志记录函数的行号,而不是调用点的行号。

使用宏。这是他们确实无法替代的地方。

编辑:

即使 C++ FAQ 也说宏有时是两害相权取其轻。

EDIT2:

正如 Nathon 在下面的评论中所说,如果您确实使用宏,最好明确说明。为您的宏指定宏名称,例如 COMMIT() 而不是 Commit()。这将使维护者和维护者清楚地了解。调试器知道正在进行宏调用,并且在大多数情况下它应该有助于避免冲突。都是好事。

So, you're looking to do logging (or something) with file & line info, and you would rather not use macros, right?

At the end of the day, it simply can't be done in C++. No matter what mechanism you chose -- be that inline functions, templates, default parameters, or something else -- if you don't use a macro, you'll simply end up with the filename & linenumber of the logging function, rather than the call point.

Use macros. This is one place where they are really not replaceable.

EDIT:

Even the C++ FAQ says that macros are sometimes the lesser of two evils.

EDIT2:

As Nathon says in the comments below, in cases where you do use macros, it's best to be explicit about it. Give your macros macro-y names, like COMMIT() rather than Commit(). This will make it clear to maintainers & debuggers that there's a macro call going on, and it should help in most cases to avoid collisions. Both good things.

千纸鹤 2024-10-09 23:25:32

您可以结合使用默认参数和预处理器技巧将调用程序文件传递给函数。它如下:

  1. 函数声明:

    static const char *db_caller_file = CALLER_FILE;
    
    类 Db {
        _Commit(const char *file = db_caller_file) {
        Log("从 %s 调用提交", file);
      }
    };
    
  2. 在类头文件中声明db_caller_file变量。
    每个翻译单元都有一个const char *db_caller_file。它是静态的,因此不会在翻译单元之间产生干扰。 (不能多次声明)。

  3. 现在是 CALLER_FILE 东西,它是一个宏,将从 gcc 的命令行参数生成。实际上,如果使用自动化的 Make 系统,其中对源文件有通用规则,则要容易得多:您可以添加一条规则来定义宏,并将文件名作为值。例如:

    CFLAGS= -MMD -MF $(DEPS_DIR)/
    lt;.d -Wall -D'CALLER_FILE="
    lt;"'
    

-D 在编译此文件之前定义了一个宏。
$< 是 Make 对规则先决条件名称的替换,在本例中是源文件的名称。因此,每个翻译单元都有自己的 db_caller_file 变量,其值为字符串,包含文件名。

相同的想法不能应用于呼叫者线路,因为同一翻译单元中的每个呼叫应该具有不同的线路号。

You can use a combination of default parameter and preprocessor trick to pass the caller file to a functions. It is the following:

  1. Function declaration:

    static const char *db_caller_file = CALLER_FILE;
    
    class Db {
        _Commit(const char *file = db_caller_file) {
        Log("Commit called from %s", file);
      }
    };
    
  2. Declare db_caller_file variable in the class header file.
    Each translation unit will have a const char *db_caller_file. It is static, so it will not interfere between translation units. (No multiple declarations).

  3. Now the CALLER_FILE thing, it is a macro and will be generated from gcc's command line parameters. Actually if using automated Make system, where there is generic rule for source files, it is a lot easier: You can add a rule to define macro with the file's name as a value. For example:

    CFLAGS= -MMD -MF $(DEPS_DIR)/
    lt;.d  -Wall -D'CALLER_FILE="
    lt;"'
    

-D defines a macro, before compiling this file.
$< is Make's substitution for the name of the prerequisite for the rule, which in this case is the name of the source file. So, each translation unit will have it's own db_caller_file variable with value a string, containing file's name.

The same idea cannot be applied for the caller line, because each call in the same translation unit should have different line numbers.

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