- 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/
我正在运行一个辅助角色,并检查 Azure 上托管的存储中是否存在数据。当我将连接字符串用于经典类型的存储时,我的代码可以正常工作,但是当我连接到 V2 Azure 存储时,它会抛出此异常。 “远程服
在我的应用程序的主页上,我正在进行 AJAX 调用以获取应用程序各个部分所需的大量数据。该调用如下所示: var url = "/Taxonomy/GetTaxonomyList/" $.getJSO
大家好,我正在尝试将我的商店导入我的 Vuex Route-Gard。 路由器/auth-guard.js import {store} from '../store' export default
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我的 Windows 计算机上的本地文件夹中有一些图像。我想将所有图像上传到同一容器中的同一 blob。 我知道如何使用 Azure Storage SDKs 上传单个文件BlockBlobServi
我尝试发出 GET 请求来获取我的 Azure Blob 存储帐户的帐户详细信息,但每次都显示身份验证失败。谁能判断形成的 header 或签名字符串是否正确或是否存在其他问题? 代码如下: cons
这是用于编写 JSON 的 NeutralinoJS 存储 API。是否可以更新 JSON 文件(推送数据),而不仅仅是用新的 JS 对象覆盖数据。怎么做到的??? // Javascript
我有一个并行阶段设置,想知道是否可以在嵌套阶段之前运行脚本,所以像这样: stage('E2E-PR-CYPRESS') { when { allOf {
我想从命令行而不是从GUI列出VirtualBox VM的详细信息。我对存储细节特别感兴趣。 当我在GUI中单击VM时,可以看到包括存储部分在内的详细信息: 但是到目前为止,我还没有找到通过命令行执行
我有大约 3500 个防洪设施,我想将它们表示为一个网络来确定流动路径(本质上是一个有向图)。我目前正在使用 SqlServer 和 CTE 来递归检查所有节点及其上游组件,只要上游路径没有 fork
谁能告诉我 jquery data() 在哪里存储数据以及何时删除以及如何删除? 如果我用它来存储ajax调用结果,会有性能问题吗? 例如: $("body").data("test", { myDa
有人可以建议如何为 Firebase 存储中的文件设置备份。我能够备份数据库,但不确定如何为 firebase 存储中的文件(我有图像)设置定期备份。 最佳答案 如何进行 Firebase 存储的本地
我最近开始使用 firebase 存储和 firebase 功能。现在我一直在开发从功能到存储的文件上传。 我已经让它工作了(上传完成并且文件出现在存储部分),但是,图像永远保持这样(永远在右侧加载)
我想只允许用户将文件上传到他们自己的存储桶中,最大文件大小为 1MB,仍然允许他们删除文件。我添加了以下内容: match /myusers/{userId}/{allPaths=**} { al
使用生命周期管理策略将容器的内容从冷访问层移动到存档。我正在尝试以下策略,希望它能在一天后将该容器中的所有文件移动到存档层,但事实并非如此在职的。我设置了选择标准“一天未使用后”。 这是 json 代
对于连接到 Azure 存储端点,有 http 和 https 两个选项。 第一。 https 会带来开销,可能是 5%-10%,但我不支付同一个数据中心的费用。 第二。 http 更快,但 Auth
有人可以帮我理解这一点吗?我创建了Virtual Machine in Azure running Windows Server 2012 。我注意到 Azure 自动创建了一个存储帐户。当我进入该存
我是一名优秀的程序员,十分优秀!