使用连接和格式文字动态分配“char*”?
Dynamically allocate `char*` with concatention and format literals?
在支持 macOS、Windows (MSVC) 和 Linux 的情况下,我该如何执行以下操作?
char *s;
func(&s, "foo");
if (<condition>) func(&s, "bar%s", "can")
/* want "foobarcan", and I don't know `strlen(s)` AoT */
我试过 asprintf
(was able to find an MSVC implementation) but that didn't seem to work well on this kind of workflow. fopencookie
and funopen
看起来很方便,但在 MSVC 上不可用。
也许 realloc
有一些干净的方法可以在 C 中创建以 char*
结尾的 NUL?
正如评论中指出的那样,(v)snprintf
始终 returns 将 写入的字节数(不包括空终止字节),即使被截断。这具有为函数提供 0
returns to-be-formatted 字符串长度的 size
参数的效果。
使用这个值,加上我们现有字符串的字符串长度(如果适用),再加一,我们(重新)分配适当的内存量。
要连接,只需在正确的偏移处打印格式化字符串即可。
一个例子,没有错误检查。
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dstr(char **unto, const char *fmt, ...) {
va_list args;
size_t base_length = unto && *unto ? strlen(*unto) : 0;
va_start(args, fmt);
/* check length for failure */
int length = vsnprintf(NULL, 0, fmt, args);
va_end(args);
/* check result for failure */
char *result = realloc(unto ? *unto : NULL, base_length + length + 1);
va_start(args, fmt);
/* check for failure*/
vsprintf(result + base_length, fmt, args);
va_end(args);
if (unto)
*unto = result;
return result;
}
int main(void) {
char *s = dstr(NULL, "foo");
dstr(&s, "bar%s%d", "can", 7);
printf("[[%s]]\n", s);
free(s);
}
stdout
:
[[foobarcan7]]
这里的警告是你不能写:
char *s;
dstr(&s, "foo");
s
必须初始化为 NULL
,或者该函数必须直接用作初始化器,第一个参数设置为 NULL
.
那个,第二个参数总是被视为格式字符串。如果第一个字符串包含不卫生的数据,请使用其他方式预分配第一个字符串。
利用示例:
/* exploit */
char buf[128];
fgets(buf, sizeof buf, stdin);
char *str = dstr(NULL, buf);
puts(str);
free(str);
stdin
:
%d%s%s%s%s%d%p%dpapdpasd%d%.2f%p%d
在支持 macOS、Windows (MSVC) 和 Linux 的情况下,我该如何执行以下操作?
char *s;
func(&s, "foo");
if (<condition>) func(&s, "bar%s", "can")
/* want "foobarcan", and I don't know `strlen(s)` AoT */
我试过 asprintf
(was able to find an MSVC implementation) but that didn't seem to work well on this kind of workflow. fopencookie
and funopen
看起来很方便,但在 MSVC 上不可用。
也许 realloc
有一些干净的方法可以在 C 中创建以 char*
结尾的 NUL?
正如评论中指出的那样,(v)snprintf
始终 returns 将 写入的字节数(不包括空终止字节),即使被截断。这具有为函数提供 0
returns to-be-formatted 字符串长度的 size
参数的效果。
使用这个值,加上我们现有字符串的字符串长度(如果适用),再加一,我们(重新)分配适当的内存量。
要连接,只需在正确的偏移处打印格式化字符串即可。
一个例子,没有错误检查。
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dstr(char **unto, const char *fmt, ...) {
va_list args;
size_t base_length = unto && *unto ? strlen(*unto) : 0;
va_start(args, fmt);
/* check length for failure */
int length = vsnprintf(NULL, 0, fmt, args);
va_end(args);
/* check result for failure */
char *result = realloc(unto ? *unto : NULL, base_length + length + 1);
va_start(args, fmt);
/* check for failure*/
vsprintf(result + base_length, fmt, args);
va_end(args);
if (unto)
*unto = result;
return result;
}
int main(void) {
char *s = dstr(NULL, "foo");
dstr(&s, "bar%s%d", "can", 7);
printf("[[%s]]\n", s);
free(s);
}
stdout
:
[[foobarcan7]]
这里的警告是你不能写:
char *s;
dstr(&s, "foo");
s
必须初始化为 NULL
,或者该函数必须直接用作初始化器,第一个参数设置为 NULL
.
那个,第二个参数总是被视为格式字符串。如果第一个字符串包含不卫生的数据,请使用其他方式预分配第一个字符串。
利用示例:
/* exploit */
char buf[128];
fgets(buf, sizeof buf, stdin);
char *str = dstr(NULL, buf);
puts(str);
free(str);
stdin
:
%d%s%s%s%s%d%p%dpapdpasd%d%.2f%p%d