- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在使用 va_list 构建一个呈现的字符串。
void Text2D::SetText(const char *szText, ...)
一切都很好,但现在用户可以在应用程序运行时更改语言。我需要重新生成所有文本字符串并在初始化后重新缓存文本位图。我想存储 va_list 并在需要生成文本时使用它。
为了提供更多背景信息,这需要在我正在翻译的 key 字符串中包含动态数据的情况下发生。
"Player Score:%d"
那是我需要翻译的关键字符串。我想保留 va_list 中提供的数字供以后使用(在初始化文本的函数范围之外),以防在初始化后需要重新翻译。我最好保留一份 va_list 的拷贝,以便与 vsnprintf 一起使用。
我对此进行了一些研究,并找到了一些方法。其中一些我质疑它是否是一种合适的方法(就稳定和便携而言)。
最佳答案
这个问题确实激起了我的兴趣。我自己的工作中也会遇到类似的问题,所以这里设计的解决方案也可能对我有帮助。
简而言之,我编写了概念验证代码,它缓存变量参数供以后使用——您可以在下面找到它。
我能够让下面的代码在 Windows 和基于英特尔的 Linux 上正常工作。我在 Linux 上用 gcc 编译,在 Windows 上用 MSVC 编译。关于从 gcc 中滥用 va_start() 有一个重复两次的警告——您可以在您的 makefile 中禁用该警告。
我很想知道这段代码是否适用于 Mac 编译器。可能需要稍作调整才能编译。
我意识到这段代码是:
我对 malloc() 和 free() 的使用是经过深思熟虑的,因为 va_list 宏来自 C 标准,而不是 C++ 特性。我知道你的问题标题提到了 C++,但除了使用一些 C++ 风格的注释之外,我还试图生成一个完全与 C 兼容的解决方案。
此代码在格式字符串处理方面也无疑存在一些错误或不可移植性。我提供这个作为概念证明,我在两个小时内一起破解,而不是准备好供专业使用的完成代码示例。
该免责声明说,我希望您能像我一样发现结果令人愉快!这是一个可爱的问题,可以深入探讨。结果的病态和扭曲性质让我大笑起来。 ;)
#include <stdio.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#define VERBOSE 0#ifdef WINDOWS#define strdup _strdup#endif/* * struct cached_printf_args * * This is used as the pointer type of the dynamically allocated * memory which holds a copy of variable arguments. The struct * begins with a const char * which recieves a copy of the printf() * format string. * * The purpose of ending a struct with a zero-length array is to * allow the array name to be a symbol to the data which follows * that struct. In this case, additional memory will always be * allocted to actually contain the variable args, and cached_printf_args->args * will name the start address of that additional buffer space. * */struct cached_printf_args{ const char * fmt; char args[0];};/* * copy_va_args -- Accepts a printf() format string and va_list * arguments. * * Advances the va_list pointer in *p_arg_src in * accord with the specification in the format string. * * If arg_dest provided is not NULL, each argument * is copied from *p_arg_src to arg_dest according * to the format string. * */int copy_va_args(const char * fmt, va_list * p_arg_src, va_list arg_dest){ const char * pch = fmt; int processing_format = 0; while (*pch) { if (processing_format) { switch (*pch) { //case '!': Could be legal in some implementations such as FormatMessage() case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case '-': // All the above characters are legal between the % and the type-specifier. // As the have no effect for caching the arguments, here they are simply // ignored. break; case 'l': case 'I': case 'h': printf("Size prefixes not supported yet.\n"); exit(1); case 'c': case 'C': // the char was promoted to int when passed through '...' case 'x': case 'X': case 'd': case 'i': case 'o': case 'u': if (arg_dest) { *((int *)arg_dest) = va_arg(*p_arg_src, int); va_arg(arg_dest, int); } else va_arg(*p_arg_src, int);#if VERBOSE printf("va_arg(int), ap = %08X, &fmt = %08X\n", *p_arg_src, &fmt);#endif processing_format = 0; break; case 's': case 'S': case 'n': case 'p': if (arg_dest) { *((char **)arg_dest) = va_arg(*p_arg_src, char *); va_arg(arg_dest, char *); } else va_arg(*p_arg_src, char *);#if VERBOSE printf("va_arg(char *), ap = %08X, &fmt = %08X\n", *p_arg_src, &fmt);#endif processing_format = 0; break; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': if (arg_dest) { *((double *)arg_dest) = va_arg(*p_arg_src, double); va_arg(arg_dest, double); } else va_arg(*p_arg_src, double);#if VERBOSE printf("va_arg(double), ap = %08X, &fmt = %08X\n", *p_arg_src, &fmt);#endif processing_format = 0; break; } } else if ('%' == *pch) { if (*(pch+1) == '%') pch ++; else processing_format = 1; } pch ++; } return 0;}/* * printf_later -- Accepts a printf() format string and variable * arguments. * * Returns NULL or a pointer to a struct which can * later be used with va_XXX() macros to retrieve * the cached arguments. * * Caller must free() the returned struct as well as * the fmt member within it. * */struct cached_printf_args * printf_later(const char *fmt, ...){ struct cached_printf_args * cache; va_list ap; va_list ap_dest; char * buf_begin, *buf_end; int buf_len; va_start(ap, fmt);#if VERBOSE printf("va_start, ap = %08X, &fmt = %08X\n", ap, &fmt);#endif buf_begin = (char *)ap; // Make the 'copy' call with NULL destination. This advances // the source point and allows us to calculate the required // cache buffer size. copy_va_args(fmt, &ap, NULL); buf_end = (char *)ap; va_end(ap); // Calculate the bytes required just for the arguments: buf_len = buf_end - buf_begin; if (buf_len) { // Add in the "header" bytes which will be used to fake // up the last non-variable argument. A pointer to a // copy of the format string is needed anyway because // unpacking the arguments later requires that we remember // what type they are. buf_len += sizeof(struct cached_printf_args); cache = malloc(buf_len); if (cache) { memset(cache, 0, buf_len); va_start(ap, fmt); va_start(ap_dest, cache->fmt); // Actually copy the arguments from our stack to the buffer copy_va_args(fmt, &ap, ap_dest); va_end(ap); va_end(ap_dest); // Allocate a copy of the format string cache->fmt = strdup(fmt); // If failed to allocate the string, reverse allocations and // pointers if (!cache->fmt) { free(cache); cache = NULL; } } } return cache;}/* * free_printf_cache - frees the cache and any dynamic members * */void free_printf_cache(struct cached_printf_args * cache){ if (cache) free((char *)cache->fmt); free(cache);}/* * print_from_cache -- calls vprintf() with arguments stored in the * allocated argument cache * * * In order to compile on gcc, this function must be declared to * accept variable arguments. Otherwise, use of the va_start() * macro is not allowed. If additional arguments are passed to * this function, they will not be read. */int print_from_cache(struct cached_printf_args * cache, ...){ va_list arg; va_start(arg, cache->fmt); vprintf(cache->fmt, arg); va_end(arg);}int main(int argc, char *argv){ struct cached_printf_args * cache; // Allocates a cache of the variable arguments and copy of the format string. cache = printf_later("All %d of these arguments will be %s fo%c later use, perhaps in %g seconds.", 10, "stored", 'r', 2.2); // Demonstrate the time-line with some commentary to the output. printf("This statement intervenes between creation of the cache and its journey to the display.\n" // THIS is the call which actually displays the output from the cached printf. print_from_cache(cache); // Don't forget to return dynamic memory to the free store free_printf_cache(cache); return 0;}
关于c++ - 在 C/C++ 中存储 va_list 供以后使用的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1562992/
尝试编译此代码时 #include void bar_ptr(int n, va_list *pvl) { // do va_arg stuff here } void bar(int n,
假设我有一个函数,它接受可变参数 (...) 或从另一个此类函数传递的 va_list 。主要逻辑在这个函数本身(我们称之为 f1),但我想让它将 va_list 传递给另一个函数(我们称之为 f2)
看似简单的问题,但一直未能在 SO 或 C 标准中找到答案。问题是 va_list 是否必须是 C 中函数的最后一个参数(当然,假设该函数将 va_list 作为参数)。 例如,这样安全吗? int
我正在尝试打印字符串类型的参数变量,但我一直卡在这上面 想法 尝试使用 _Str[i] 作为 while 循环内的表达式在 srting 内部移动,一旦 _Str[i] == '\0' 返回 (-1
下面的 max 函数应该返回 5,但它返回的是 4294967294。我怀疑奇怪的行为是由变量转换引起的,但无法弄清楚。有人能检测出故障吗? 系统:Windows 7(64位),mingw64 #in
在 Fedora 11 上编译一些工作代码时,我收到此错误: /usr/include/c++/4.4.1/cstdarg:56: error: ‘::va_list’ has not been de
全部, 我想控制 va_list 中的传递参数的数量。 va_list args; va_start(args, fmts); vfprintf(stdout, fmts, args)
我有一个很好的 C++ 函数,它通过 va_list + va_start + va_arg 支持多个参数。但我必须将我的项目转换为 C。转换后,这个 va_list 构造被编译器拒绝(多个错误)。有
我已经编写了这段代码,但我不确定它是否可以。 size_t sendHeaders(int fd, int seconds, const char* header1, ...) { size_
我无法找到我的“问题”的答案。 我创建了一个函数,它接受不同数量的整数('findMinVal(int x, ...)')并返回所有调用中的最小数字。现在我的程序直接通过代码获取参数: int mai
我一直在追踪一个问题,并将范围缩小到这个框架: #include #include #include #include #include #include typedef struct _
我有一个主要更新,我在通话前进行访问控制。我想在我的代码中使用一个地方来调用任何紧急函数。 我有一个结构 ACTION: { FUNC_PROTOTYPE pfnAction; uns
我目前有 2 个函数重载: void log(const char* format, ...); void log(const string& message); 我希望在这个调用的情况下:log("
在 case 's' 下,我得到一个坏指针 (0xcccccccc) 异常: string Logger::format(const char *str, va_list args) { os
#include #include void s(const char* param, ...) { va_list arguments; va_start (arguments,
我试着写一个这样的函数: int solve(double* x, double xA, double xB, double zeps, double funct(double x
我有这样的代码 #include "atlstr.h" void DisplayMessage(CString pszFormat, ...) { CString str; va_l
我正尝试在 C++ 中为一个项目实现一种反射形式。这个想法是,您将带有标签的类作为一种模板注册到映射中,然后调用共享基类的 cloneNew 方法来实际创建您想要的对象。但是,当我尝试使用 va_li
我已经(简单地)编写了这段代码。但它需要两次修复才能确定。 size_t send_header(int fd, int seconds, const char* header1, ...) {
我有一个用于微 Controller 的以太网库(用于 lpc2478 的 keil rl-tcpnet)。库以这种方式在调试输出函数中使用 va_list(指向 stdarg.h 中定义的 arg
我是一名优秀的程序员,十分优秀!