【问题标题】:Working with strings in c and c++在 c 和 c++ 中处理字符串
【发布时间】:2012-10-01 03:28:21
【问题描述】:

我不确定如何将不同的字符串类型传递给 C 中的函数。

我有一个接收格式化字符串的函数

void Logger::info(const char *logstring, ...) 
{

    // So I basically can write a preliminary message "DATA:" to a buffer
    // and then use vsnprintf() to write the const char *logstring to the buffer as well.

    int offset = 0;
    va_list argp;
    char buf[STRSIZE + 1];

    va_start(argp, logstring);
    offset = sprintf(buf, "DATA: ");
    vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
    va_end(argp);

    // Then I write the buffer to stderr

    fprintf(stderr, "%s\n", buf);
}

我想做的是将所有这些更深入地移动到函数中。但我不能让它工作,因为我不知道如何成功地将格式化字符串“logstring”传递给函数并让它从另一边出来。

所以我想这样做......

info(const char *logstring, ...)
{
    writeToFile("Data:",logstring);
}

然后我可以更集中地完成日志文件的写入。

【问题讨论】:

  • 您是否在问如何将可变参数从您的顶级函数发送到 writeToFile() 函数?或者如何执行格式,然后将序言和格式化数据发送到 writeToFile() ?也许两者都不是,你在问别的吗?抱歉,对这个问题有点困惑。
  • 也差不多。我希望能够将“const char *logstring”传递给函数。因此,如果我可以只需要将我的函数变量更改为接受它的东西,或者只是将其转换为可以通过的东西,那就更好了。我会举例说明我尝试过的方法,但由于它们不起作用,因此会使事情变得混乱。要么以某种方式作为一个字符串出现,要么丢失了应该在字符串中的格式化变量。
  • 好的。我觉得我明白了。我可以尝试制定一个答案,但我想只是告诉你可以创建一个以 va_list 作为参数的函数(事实上,vsnprintf 就是这样一个例子)。具有讽刺意味的是,您在这里的代码看起来拥有您需要的一切,只是没有在正确的地方完成您想要的。

标签: c string char constants formatted


【解决方案1】:

好的,很可能我没有得到您在此处寻找的确切位置,但愿意试一试并烧掉答案。以下是尽可能基本的记录器,但演示了如何集中消息构建。底部包含一些测试条件,我特意缩小了初始缓冲区大小,以便您在调试器中浏览并以交互方式查看调整大小。毫无疑问,您会想放大它的大小。

无论如何,如果我碰巧碰巧并正确理解了这个问题,我希望如果它不能直接解决您的问题,您至少会得到一些想法。谢谢。

编辑:OP 请求使用 std::string 和缓冲区大小调整来静噪,以符合其嵌入式系统环境的有限编译能力。因此,使用了固定长度的缓冲区,并且来自vsnprintf() 的输出只有在内容实际适合时才受信任。

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

class Logger
{
    static const size_t STRSIZE = 256;

public:
    void error(const char* fmt, ...)
    {
        va_list argptr;
        va_start(argptr,fmt);
        log("ERROR", fmt, argptr);
    };

    // two different logging interfaces.
    void info(const char* fmt, ...)
    {
        va_list argptr;
        va_start(argptr,fmt);
        log("INFO", fmt, argptr);
    };

    void debug(const char* fmt, ...)
    {
        va_list argptr;
        va_start(argptr,fmt);
        log("DEBUG", fmt, argptr);
    };

private:
    void log(const char *msg, const char* fmt, va_list& vl)
    {
        // uses a fixed size message buffer
        char str[STRSIZE+1] = {0};
        strncpy(str, msg, sizeof(str)-1);
        strncat(str, ": ", (sizeof(str)-1) - strlen(str));

        // needed for sizing limits of variadic printf, then send
        //  output as a single line message to stderr.
        size_t mlen = strlen(str);
        if (vsnprintf(str + mlen, sizeof(str)-mlen-1, fmt, vl) >= 0)
            fprintf(stderr, "%s\n", str);
        else
            fprintf(stderr, "%s: (max log message length exceeded)\n", msg);
    };
};

int main(int argc, char *argv[])
{
    Logger logger;

    logger.debug("Numbers %d %d %d", 1,2,3);
    logger.error("Strings %s %s %s", "1", "2", "3");
    logger.info("Mixed %s %d %p", "1", 2, "3");
    logger.info("No additional parameters required for this message.");

    // demonstrate automatic cutoff.
    char sbig[] = "0123456789012345678901234567890123456789"
                  "0123456789012345678901234567890123456789";

    logger.debug("Oversized params: %d-%s %d-%s %d-%s %d-%s", 
                 1, sbig, 2, sbig, 3, sbig, 4, sbig);
    return 0;
}

【讨论】:

  • 不确定为什么要使用 std::string str 创建字符串?特别是如果你不推荐它?我可以使用字符缓冲区 [bufsize] 吗?我还能 "fprintf(location, "%s\n", str);" str 值?
  • 它使用的 std::string 后面的缓冲区的动态增长。请注意调整大小的循环,直到输出最终适合。如果您可以忍受潜在的部分输出和固定的最大输出长度,那么肯定会抛出循环并确保您为 vsnprintf 的 maxlen 使用固定的缓冲区大小,除此之外,这个想法非常简单。最后,如果您正在使用 fprintf(),请确保输出缓冲区已终止。
  • 好吧,即使我包含了 string.h,我似乎也没有 std::string。我在嵌入式系统上,所以如果没有安装软件包,它可能就不存在。空终止的最简单方法是什么?我虽然你只需要一个至少比写入字符串长一个字符的缓冲区?
  • std::string 是标准模板。如果不在您的嵌入式编译环境中,则可以将其剥离,Sample 已被修改为不使用 std::strings 而是使用固定缓冲区,并在输出长度超过最大长度时警告您。我希望它更符合您的需要。
猜你喜欢
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
相关资源
最近更新 更多