【问题标题】:Size in bytes of ellipsis function arguments省略号函数参数的字节大小
【发布时间】:2012-04-24 12:20:09
【问题描述】:

我有一个功能:

static int myprintf(const char* fmt, ...)

我想知道所有 myprintf 参数的字节大小,如果它们被打印到缓冲区。 我需要动态分配一个可以打印参数的数组(使用sprinf_vsprinf) 例如在 32 位操作系统中,对于 myprintf("%d %c",10,'a'); myprintf 参数的大小为 5。

我尝试像这样实现它:

va_list ap;

va_start(ap, fmt);

myArgSize(ap);

有人可以建议如何实现 myArgSize。

有人告诉我尝试这样的事情

char c;
int len = ::_vsnprintf(&c, 1, fmt, ap);

它不起作用,因为写入了多个字节。 但可能有一些解决方法。

谢谢

【问题讨论】:

  • 你说“myprintf 参数的大小是 5”。但如果我明白你在问什么,不,它是堆栈上的 8 个字节。 4 代表 int,4 代表 ehm,另一个 int。在 32 位系统上,可变参数函数中的所有值都是 4 个字节,浮点值除外。 floatdouble 是 8 个字节。并提防long double
  • 您是否对用于字符串表示的字符数或用于值本身的字节数感兴趣?这些是完全不同的,例如以十进制打印时,4 字节整数可能需要 1 到 10 个字符。
  • @MrLister:你抽烟吗? 'a' 是 C++ 中的一个字符,根据 sizeof 的定义,它具有 sizeof(char) == 1。在大多数机器上,char 是 1 个字节。
  • @MrLister:这不是完全依赖于实现吗?例如,他可以使用自定义调用约定,或者编译器可以内联调用。而且我不认为他的意思是“用于调用函数的堆栈的超级实现依赖大小”,无论如何这将大于参数。参数本身只有一个大小。任何给定的实现可能希望使用比堆栈上更多的空间这一事实是无关紧要的。而且我很确定将错误的格式说明符传递给printf 完全是UB,所以你的例子没有任何意义。
  • @unwind:一个涉及::func()语法的C题?不会发生。 @MikeSeymour:现在这是一个理性的论点,可能会使结果蒙上阴影。毕竟,我想这取决于你认为的“论点”。 @Yakov:是的,我不得不重新编辑。下次多注意一点。

标签: c++ c printf variadic-functions


【解决方案1】:

尽管您的大部分问题是关于传递给三元函数的参数的大小,但在我看来,您实际上对输出缓冲区需要多大感兴趣。尝试以下方法:

va_list ap;

va_start(ap, fmt);

int len = ::vsnprintf( NULL, 0, fmt, ap);
if (len < 0) abort();

char* buffer = (char*) malloc( len + 1);
if (!buffer) abort();

::vsnprintf( buffer, len+1, fmt, ap);

va_end();

但是,如果您的平台没有符合 C99 标准的 vsnprintf()(例如 MSVC),那么您将不得不进行一些调整。对于 MSVC,您可以尝试传入一个猜测大小的缓冲区(可能是 strlen(fmt)+1 + (10 * number_of_percent_signs_in_fmt) 或者只是从一个应该覆盖 99% 的案例的大小开始 - 可能是 200),并增加猜测直到它起作用。或者你可以试试the snprintf() family of functions by Holger Weiss

【讨论】:

    【解决方案2】:

    嗯...关于参数类型和顺序的唯一信息在第一个参数中;这就是为什么它是必需的。

    对于printf()-like 函数,你需要遍历格式化字符串,解析每个%-code,并添加对应类型的大小。这不会是微不足道的。记住要处理像%hd 这样的东西,它需要short 而不是int。此外,将值传递给可变参数函数时会发生转换。

    【讨论】:

    • 除了他的问题只标记了C++
    • @DeadMG 不是现在......我不认为这是我第一次找到它的时候。
    • 哦,他刚刚又编辑回来了?我讨厌无法确定他们使用哪种语言的提问者。编辑:有人else重新标记它C。它不在C中。C没有::func() 语法。 C++ 可以。所以它必须用 C++ 编写。
    • @DeadMG 好点,没看到那些。我已经编辑了我的答案的 C 特定部分。
    【解决方案3】:

    您可以使用vasprintf 将所有格式设置到一个大小合适的缓冲区中,它将分配(您必须free)。

    或者,vsnprintf 可用于获取字符串的长度,printf 将打印:

    int n = vsnprintf(NULL, 0, fmt, args);
    

    这是因为如果它有足够的空间,它会返回它将打印的字节数。在这种情况下,它不能打印任何东西,但无论如何都会返回数字。

    【讨论】:

      【解决方案4】:

      您可以使用 sizeof(type_name) 并使用 for 循环遍历所有参数, type_name 是任何 c 数据类型,如 int、float、long 等。 然后添加所有字节,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 2022-10-14
        • 2013-06-27
        • 2022-01-24
        • 2015-01-26
        • 1970-01-01
        相关资源
        最近更新 更多