将 C 打印登录到 stdout 和 stderr 而没有重复

Logging in C printing to both stdout and stderr without duplicates

我已经为我的 C 命令行程序实现了自己的消息记录功能,我希望能够将信息消息打印到 stdout,将错误消息打印到 stderr,并将警告消息打印到 stderr如果它们输出到相同的位置,则两者都没有重复的消息。

信息和错误消息工作正常,但对于警告消息,我不知道如何有效地检查 stdout 和 stderr 文件流是否指向相同的输出位置。我的代码有效,但我不明白为什么,因为从逻辑上讲,如果 stdoutstderr 指向同一个文件,则在单步执行函数时它应该产生重复的条目。

我检查过 stdoutstderr 有相同的输出文件,它们仍然在指针中产生不同的内存地址并且 fileno(stdout)fileno(stderr) 不同.

tl;dr 我有可用的代码,但据我所知......它不应该。任何人都可以帮助解释它为什么有效或者有谁知道解决这个问题的正确方法。

编辑:我调用程序的方式是:myProgram >out.lis 2>out.lis

编辑 2:当这样调用时它确实会产生重复项:myProgram >out.lis 2>&1

我的警告消息代码:

/* Warning message, a unified function for printing warning messages */
/* Warning messages are printed to both the output log and the error log (if different) */
void warningMessage(char * msg) {
    if (isatty(fileno(stderr))) {
        /* Add color if printing to terminal */
        fprintf(stderr, "3[0;31;43mWarning: 3[0;30;43m%s3[39;49m\r\n", msg);
    } else {
        fprintf(stderr, "\nWarning: %s\n", msg);

        if (isatty(fileno(stdout))) {
            fprintf(stdout, "3[0;31;43mWarning: 3[0;30;43m%s3[39;49m\r\n", msg);
        } else {
            fprintf(stdout, "\nWarning: %s\n", msg);
        }
    }
}

有关我的代码的任何其他指示也会有所帮助!我最近才开始学习 C!

技巧将是 fstat()。

获取两者的 fileno()(应该分别为 1 和 2,但对于非 Unix 操作系统可能有所不同),将它们作为第一个参数传递给 fstat(),并比较作为第二个填充的结构范围。如果它们输出到同一个地方,我希望完全匹配。我相信时间戳可能会有所不同。

恐怕我不能告诉你 MS-Windows 是否有相同的调用,但它应该有一个等价物。

别忘了适当冲洗。

编辑:

指出您只需要 检查两个字段。这是正确的(除了一些奇怪的文件系统)。

可能会发生一些奇怪的事情。如果同一设备有两个设备节点(如 /dev/tty1 和 /dev/tty1_alternate 指向同一设备),则 st_ino 将不匹配,但 st_rdev 匹配。我会把它们当作不同的,因为用户正在和你一起玩游戏。

尝试检查这两个打开是否相同也可能很好。 (处理 myprogram >out 2>out 案例。) 为此,您可能需要弄乱一些参数,看看改变一个参数是否会改变另一个参数。可能是 fcntl() 函数,使用 F_GETFL 和 F_SETFL.

you could use fstat中提到的检查文件描述符真正写入的位置。

在 POSIX 系统上,您使用 stat structure 成员 st_devst_ino 来找出使用了哪些文件。如果这两个成员对于 stdoutstderr 都是相等的,那么您正在写入同一个文件。

我还建议您在程序的早期只一次进行此检查。重定向只发生一次,您无需在每次要写消息时都检查它。