在 C++ 中重用 strftime

Reusing strftime in C++

我正在编写一个程序,需要将当前日期和时间写入日志文件,虽然代码可以运行,但有很多重复代码。密码是

#include<iostream>
#include<fstream>
#include<unistd.h>

using namespace std;

string logFile="/home/shared/c++/time.log";
char timeBuffer[80];

int main()
{
     struct tm * timeInfo;
     time_t rawtime;

     ofstream vLog(logFile.c_str(), ios_base::app | ios_base::out);
          {
               {
                    time (&rawtime);
                    timeInfo = localtime(&rawtime);
                    strftime(timeBuffer,sizeof(timeBuffer),"%A %d %b %Y %r %Z",timeInfo);
                    string timeNow(timeBuffer);
                    cout << timeNow << " - Start of log." << endl;
                    vLog << timeNow << " - Start of log." << endl;
               }
               // Do a part of the code
               {
                    time (&rawtime);
                    timeInfo = localtime(&rawtime);
                    strftime(timeBuffer,sizeof(timeBuffer),"%r",timeInfo);
                    string timeNow(timeBuffer);
                    cout << " " << timeNow << " - 1st Line of log." << endl;
                    vLog << " " << timeNow << " - 1st Line of log." << endl;
               }
               // Do more code
               {
                    time (&rawtime);
                    timeInfo = localtime(&rawtime);
                    strftime(timeBuffer,sizeof(timeBuffer),"%r",timeInfo);
                    string timeNow(timeBuffer);
                    cout << " " << timeNow << " - 2nd Line of log." << endl;
                    vLog << " " << timeNow << " - 2nd Line of log." << endl;
                }
                // Do the last part of the code
                {
                    time (&rawtime);
                    timeInfo = localtime(&rawtime);
                    strftime(timeBuffer,sizeof(timeBuffer),"%A %d %b %Y %r %Z",timeInfo);
                    string timeNow(timeBuffer);
                    cout << timeNow << " - End of log." << endl;
                    vLog << timeNow << " - End of log." << endl;
                }
        }
}

我不得不在每一节中包含 { },以便变量仅用于一个特定的代码块。如果我不使用它们,那么我会在编译时出错。

time.cpp: In function "int main()":
time.cpp:54:29: error: redeclaration of "std::string timeNow"
    string timeNow(timeBuffer);
                             ^
time.cpp:45:11: error: "std::string timeNow" previously declared here
    string timeNow(timeBuffer);
           ^

加上大括号,编译运行没有问题。

写入日志文件的信息会有所不同,需要和时间分开。

由于我是 C++ 的新手,我觉得我把问题复杂化了,所以任何指导将不胜感激。 我是 运行 CentOS 7,g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11)

问候 琥珀玛丽

更新

感谢您的帮助。完整代码如下:

#include<iostream>
#include<fstream>
#include<unistd.h>

std::string logFile="/home/shared/c++/time.log";
char timeBuffer[80];
void getTime(std::ofstream &vLog, const std::string &format_args, const std::string &message)
{
    struct tm * timeInfo;
    time_t rawtime;
    time (&rawtime);
    timeInfo = localtime(&rawtime);
    strftime(timeBuffer,sizeof(timeBuffer),format_args.c_str(),timeInfo);
    std::string timeNow(timeBuffer);
    std::cout << timeNow << message << std::endl;
    vLog<< timeNow << message << std::endl;
}

int main()
{
    std::ofstream vLog(logFile.c_str(), std::ios_base::app | std::ios_base::out);
    getTime(vLog, "%A %d %b %Y %r %Z", " - Start of logging");
    // Do part of the code
    getTime(vLog, " %r", " - 1st line of log");
    // Do more code
    getTime(vLog, " %r", " - 2nd line of log");
    // Do the last part of the code
    getTime(vLog, "%A %d %b %Y %r %Z", " - End of logging");
    vLog << std::endl;
    return (0);
}

希望对其他人有所帮助。

琥珀玛丽

问题是您正在重新声明变量 "timeNow" 并调用其构造函数以赋予其值 "timeBuffer"。这适用于括号,因为每个括号都是一个新范围。 "timeNow" 的每个重新声明对其所有其他声明都是不可见的,因此编译器方面没有混淆。要摆脱这种情况,请使用赋值而不是尝试重新声明变量。使用 timeNow = timeBuffer

而不是

string timeNow(timeBuffer);

我试过这段代码,它在我这边使用 g++ 工作:

 int main()
    {
         struct tm * timeInfo;
         time_t rawtime;

         ofstream vLog(logFile.c_str(), ios_base::app | ios_base::out);


                        time (&rawtime);
                        timeInfo = localtime(&rawtime);
                        strftime(timeBuffer,sizeof(timeBuffer),"%A %d %b %Y %r %Z",timeInfo);
                        string timeNow(timeBuffer);
                        cout << timeNow << " - Start of log." << endl;
                        vLog << timeNow << " - Start of log." << endl;

                   // Do a part of the code

                        time (&rawtime);
                        timeInfo = localtime(&rawtime);
                        strftime(timeBuffer,sizeof(timeBuffer),"%r",timeInfo);
                        timeNow = timeBuffer;
                        cout << " " << timeNow << " - 1st Line of log." << endl;
                        vLog << " " << timeNow << " - 1st Line of log." << endl;

                   // Do more code

                        time (&rawtime);
                        timeInfo = localtime(&rawtime);
                        strftime(timeBuffer,sizeof(timeBuffer),"%r",timeInfo);
                        timeNow = timeBuffer;
                        cout << " " << timeNow << " - 2nd Line of log." << endl;
                        vLog << " " << timeNow << " - 2nd Line of log." << endl;

                    // Do the last part of the code

                        time (&rawtime);
                        timeInfo = localtime(&rawtime);
                        strftime(timeBuffer,sizeof(timeBuffer),"%A %d %b %Y %r %Z",timeInfo);
                        timeNow = timeBuffer;
                        cout << timeNow << " - End of log." << endl;
                        vLog << timeNow << " - End of log." << endl;
}

编写一个函数来包装您的代码。参数应该是 ofstream、strftime 格式参数和日志消息(“- 第一行代码”,..)

void foo(ofstream &vLog, const string &format_args, const string &message)
{
    struct tm * timeInfo;
    time_t rawtime;

    time (&rawtime);
    timeInfo = localtime(&rawtime);
    strftime(timeBuffer,sizeof(timeBuffer),format_args.c_str(),timeInfo);
    string timeNow(timeBuffer);
    cout << timeNow << message << endl;
    vLog<< timeNow << message << endl;
}

int main()
{
    ofstream vLog(logFile.c_str(), ios_base::app | ios_base::out);

    foo(vLog, "%A %d %b %Y %r %Z", " - 1st Line of log.");
    // Do a part of the code
    foo(/* second call */);
    // Other stuff
    foo(/* 3rd call */);
    // ...

    return 0;
}

是的,这是可能的:)

让我们首先考虑整个获取和格式化时间业务。重复代码中唯一可变的是格式字符串,所以让我们把它作为一个参数:

std::string formattedCurrentTime(char const *const format) {
    std::time_t const rawTime = std::time(nullptr);
    std::tm const *const timeInfo = std::localtime(&rawTime);

    char buffer[80];
    std::size_t const length = std::strftime(buffer, sizeof buffer, format, timeInfo);

    return {buffer, buffer + length};
}

然后我们可以查看重复的日志行。由于整个 operator << 重载和多态性业务,通用解决方案实施起来有点棘手,但您的案例看起来足够一致,可以从量身定制的解决方案中受益:

auto const logBookend = [&](std::string const &message) {
    auto const timeNow = formattedCurrentTime("%A %d %b %Y %r %Z");

    std::cout << timeNow << " - " << message << std::endl;
    vLog      << timeNow << " - " << message << std::endl;
};

auto const logLine = [&](std::string const &message) {
    auto const timeNow = formattedCurrentTime("%r");

    std::cout << timeNow << " - " << message << std::endl;
    vLog      << timeNow << " - " << message << std::endl;
};

注意:请参阅 this question 为什么 使用 using namespace std;

See it live on Coliru!