C++ 从自定义printf函数返回常量char*
我已经编写了一个自定义打印函数。我的问题是我需要返回一个C++ 从自定义printf函数返回常量char*,c++,c,printf,variadic-functions,C++,C,Printf,Variadic Functions,我已经编写了一个自定义打印函数。我的问题是我需要返回一个const char*,因为它必须在另一个函数中使用。我根本不知道该怎么办 另一个函数(const char*text/*Here*/,unsigned\uu int32值,unsigned\uu int64 bigVal) 我知道下面的示例不能正常工作。这就是我到目前为止所尝试的 const char* CatchMessage (const char *message, ...) { va_list args; va_
const char*
,因为它必须在另一个函数中使用。我根本不知道该怎么办
另一个函数(const char*text/*Here*/,unsigned\uu int32值,unsigned\uu int64 bigVal)代码>
我知道下面的示例不能正常工作。这就是我到目前为止所尝试的
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);
}
电话:
应返回:
"Some Input stuff and 12 equals to 6"
我一直未能找到解决办法。任何帮助都将不胜感激
问:如何让这个CatchMessage
函数返回格式正确的const char*
?听起来CatchMessage
应该将指针指向一个char缓冲区(及其大小)并放入该缓冲区
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;
}
请参阅以供参考
<>和GLGLL:如果您想使用干净的方式,使用<代码> VSNPRETCF(结果、大小、消息、ARG)< /Calp>> P>因为您使用C++(至少根据问题的标签)为什么不返回字符串在<代码> STD::String ?/P> < P>返回一个问题(<代码> const )char*
就是你必须在某个地方有一个缓冲区
有几种方法可以实现这一点:
调用方必须提供该缓冲区
您必须malloc()
it
函数本身作为一个静态缓冲区,但这会使它不可重入-这对多线程等不利
广告1:
打电话给
char buffer[500];
CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
anotherfunction(buffer, ...)
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
char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
anotherfunction(buffer, ...)
广告2:
广告3:
打电话给
char buffer[500];
CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
anotherfunction(buffer, ...)
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
char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
anotherfunction(buffer, ...)
没有其他选择,尤其是没有定义
char result[500];
在函数中,然后返回:此数组位于堆栈上,并在返回后立即释放。调用者无法安全地访问它;它的内容只是未定义。如果您不关心重新进入,您可以返回指向静态缓冲区的指针:
#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兼容的,那么您可以使用NULL
调用第一个vsprintf
,作为第一个参数来了解结果字符串长度,然后分配该端的缓冲区
在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'.
在一般情况下,它稍微有点毛茸茸的,因为您需要解析修饰符等等。。。但是,对于生产就绪的实现,我建议看一下Boost.Format。我建议检查您的系统是否有vasprintf()
或vs[n]printf()
(后者可以调用两次,一次使用空缓冲区获取输出长度,然后在缓冲区上再次调用malloc
/new
)。。。您的客户端代码需要负责释放内存。但是,这有什么意义呢?你有没有考虑过boost::format
和std::string
?当然没有。结果
指向哪里?为什么vsprintf()
而不是vsnprintf()
?对不起,我的坏:)忘记将void更改为char*。为什么是vsprintf?因为如果他阅读我链接的文档,他会自己找到安全的方法;)如果生成的字符串超过500个字符呢?不,你不能-那就太晚了,代码已经编译好了。使用vsnprintf()
有什么问题?然后所有的问题都消失了。不,它们不是:你的数组是如何生存的?它也被标记为C++ +ToTuna:最后我听说它被推荐在C++中使用RAII;真正的问题在于,最佳答案很大程度上取决于你是否想要C或C++解决方案。当然,C++中可以使用C解决方案;但是为什么要标记它C++呢?它什么也没有带来。就我而言,任何C++标记的问题都要用C++ 11的全部强度(最好是实践)来回答,除非有OP的特殊要求。我想有人用C标记了一个问题,需要C解决方案。如果他们把这两者都贴上标签,我怀疑他们是在混合环境中使用的。也许它可以是使用C++方法的代码,但是接口必须匹配C。在这种情况下,在中间代码中使用STD::string是有效的。但他说他需要一个常量字符,很可能他不能改变这个要求。告诉他返回一个std::string不会有多大帮助。他需要用一个char const*
调用另一个函数,但是std::string
提供了这一点(使用c_str
);不清楚的是,所说的另一个功能是否拥有所有权。如果没有:另一个函数(格式(…).c_str(),…)代码>完全匹配,C++中的临时生命周期规则保证<>代码> STD::String >在代码> > Actudio< <代码>调用结束后,将被销毁,这是完美的。老实说,这个问题确实是在指定的:(我把它标记成C和C++,因为我对两种解决方案都是开放的。这不是一个很大的问题来解决它们之间的差异。我知道STD::String将在正常情况下工作,但是在这种情况下我不能使用它。(无论如何谢谢。+ 1)
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'.
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