我已经编写了自定义打印功能。我的问题是我需要返回一个const char*
,因为这必须在另一个函数中使用。我根本不知道如何管理......
anotherFunction (const char* text /*Here*/, unsigned __int32 value, unsigned __int64 bigVal);
我知道以下示例/ s不能正常工作。那是我迄今为止所尝试过的。
const char* CatchMessage (const char *message, ...)
{
va_list args;
va_start (args, message);
/*?*/
va_end (args);
return message;
}
我只是设法在cmd中获得正确的输出,但实际上我需要它作为返回值。
void CatchMessage (const char *message, ...)
{
va_list args;
va_start (args, message);
vfprintf (stdout, message, args);
va_end (args);
}
呼叫:
CatchMessage ("Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
应该返回:
"Some Input stuff and 12 equals to 6"
我一直无法找到解决方案。任何帮助将不胜感激。
问:如何让此CatchMessage
函数返回格式正确的const char*
?
答案 0 :(得分:6)
听起来CatchMessage
应该指向char缓冲区(及其大小),vsnprintf()
指向该缓冲区。
答案 1 :(得分:3)
由于您正在使用C ++(至少根据问题上的标签),为什么不在std::string
中返回字符串?
答案 2 :(得分:2)
返回(const
)char *
的问题是你必须在某个地方有一个缓冲区。
有几种方法可以实现这一目标:
malloc()
static
缓冲区,但这会使其不可重入 - 这对于多线程等是不利的。广告1:
void CatchMessage(char * result, size_t maxlen, const char *message, ...)
{
va_list ap;
va_start(ap, message);
vsnprintf(result, maxlen, message, ap);
va_end(ap);
}
用
调用char buffer[500];
CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
anotherfunction(buffer, ...)
ad 2:
char * CatchMessage(const char *message, ...)
{
size_t size = 500;
char * result = malloc(size);
if (!result) return NULL; // error handling!
while (1) {
va_list ap;
va_start(ap, message);
size_t used = vsnprintf(result, size, message, ap);
va_end(ap);
char * newptr = realloc(result, size);
if (!newptr) { // error
free(result);
return NULL;
}
result = newptr;
if (used <= size) break;
size = used;
}
return result;
}
用
调用char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
if (!buffer) { /* error handling: no memory! */ }
anotherfunction(buffer, ...)
free(buffer); // important for avoiding memory leaks
广告3:
char * CatchMessage(const char *message, ...)
{
static char result[500]; // static is important here! Otherwise the memory will be freed immediately after returning.
va_list ap;
va_start(ap, message);
vsnprintf(result, sizeof result, message, ap);
va_end(ap);
return result;
}
用
调用char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
anotherfunction(buffer, ...)
没有其他选择,尤其是没有定义
char result[500];
函数中的然后返回它:这个数组存在于堆栈中并在返回后立即释放。呼叫者无法安全访问它;它的内容是未定义的。
答案 3 :(得分:1)
如果你不关心重新入侵,你可以返回指向静态缓冲区的指针:
#define MESSAGE_MAX 1024
const char *
CatchMessage (const char *message, ...)
{
static buffer[MESSAGE_MAX];
va_list args;
va_start (args, message);
vsnprintf (buffer, MESSAGE_MAX, message, args);
va_end (args);
return buffer;
}
注意:
此实现不是线程安全的。如果您关心线程安全,请使用线程本地存储而不是静态缓冲
此实现具有硬编码的邮件长度上限。如果这不合适,并且您的编译器符合C99,则可以使用vsprintf
作为第一个参数调用NULL
来了解结果字符串长度,然后分配该侧的缓冲区。
答案 4 :(得分:0)
在C ++中,可变参数的使用是坏,因为它特别强调类型安全性(和内存安全性)。因此,您可能想要提出一个实际上类型安全的版本(是的,这是可能的),并提出了类似的接口:
template <typename H, typename... Args>
void format(std::ostream& out,
char const* format,
size_t len,
H const& head,
Args const&... args);
// Variations with 'char const (&)[N]' and 'std::string' formats
// as well as variations returning directly a 'std::string'.
现在,format
的实施并不太难;特别是不支持位置参数。简单的一个可以在下面找到:
inline void format_string(std::ostream& out, char const* const* c) { out << *c; }
inline void format_string(std::ostream& out, std::string const* s) { out << *s; }
inline void format_string(std::ostream& out, void const*); // will throw
template <typename Integral, typename = enable_integral<Integral>::type>
inline void format_integral(std::ostream& out, Integral const* i) { out << *i; }
inline void format_integral(std::ostream& out, void const*); // will throw
inline size_t format_consume(std::ostream& out,
char const* const format,
size_t const length)
{
char const* end = format + length;
char const* current = format;
do {
// 1. Find first "format identifier", output stuff in-between
char const* perc = std::find(current, end, '%');
if (perc != current) { out.write(current, perc - current); }
current = perc;
// 2. %% is % escaped by %, so output it directly
while (*current == '%' and *(current + 1) == '%') {
out.put('%');
current += 2;
}
} while (current != end and *current != '%');
// 3. Return number of characters of format parameter consumed
return current - format;
} // format_consume
inline void format(std::ostream& out, char const* format, size_t len) {
size_t const consumed = format_consume(out, format, len);
if (consumed != len) { throw std::runtime_exception("Missing arguments"); }
} // format
template <typename H, typename typename... Args>
void format(std::ostream& out,
char const* format,
size_t len,
H const& head,
Args const&... args)
{
size_t const consumed = format_consume(out, format, len);
if (consumed == len) { throw std::runtime_exception("Extraneous arguments"); }
format += consumed;
len -= consumed;
assert(*format == '%');
switch(*(format+1)) {
case 's': format_string(out, &head); break;
case 'd': format_integral(out, &head); break;
default: throw std::runtime_exception("Invalid specifier");
}
format(out, format+2, len-2, args...);
} // format
在一般情况下,它稍微多毛,因为你需要解析修饰符等...但是,对于生产就绪的实现,我建议看一下Boost.Format。
答案 5 :(得分:-3)
char* CatchMessage (size_t size, const char *message, ...)
{
char result[size];
va_list args;
va_start (args, message);
vsprintf (result, message, args);
va_end (args);
return result;
}
请参阅this以供参考。
对于glglgl:如果你想使用干净的方式,请使用vsnprintf(result, size, message, args)