我在C ++环境中使用了一些C函数。而且我收到以下警告,因为C ++不允许将字符串文字分配给char *
类型。
C ++ 11不允许从字符串文字转换为char *
我的代码:
void sys_vgui(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
//do something
va_end(ap);
}
void open(t_buf *x)
{
sys_vgui("wm deiconify .x%lx\n", x);
sys_vgui("raise .x%lx\n", x);
sys_vgui("focus .x%lx.text\n", x);
}
我可以通过将字符串文字转换为以下内容来消除这些警告。
sys_vgui(const_cast<char *>("wm deiconify .x%lx\n"), x);
sys_vgui(const_cast<char *>("raise .x%lx\n"), x);
sys_vgui(const_cast<char *>("focus .x%lx.text\n"), x);
但是我不确定它是否真的安全,因为我已经看到很多人说不要直接将字符串文字转换为char *
。
所以我想出了以下似乎更安全的解决方案。
char str1[] = "wm deiconify .x%lx\n";
sys_vgui(str1, x);
char str2[] = "raise .x%lx\n";
sys_vgui(str2, x);
char str3[] = "focus .x%lx.text\n";
sys_vgui(str3, x);
但这使我的代码变得肮脏且难以维护,因为每当我使用该函数时,都必须使用不同的名称(例如str1,str2,str3 ...)创建多个变量。
所以我的问题是:
1)就我而言,使用const_cast<char *>
真的不安全吗?
2)有什么解决方案可以使用char
数组编写干净的代码,而不必使用不同的名称创建多个变量?
答案 0 :(得分:3)
只要sys_vgui
不修改字符串是安全的,这大概不是因为修改字符串文字在C中const
具有未定义的行为。所以如果你有类似的东西
sys_vgui("wm deiconify .x%lx\n", x);
在C中,则带有const_cast
的C ++版本同样安全。
但是,为了消除C ++代码的丑陋性,我可能会编写一个包装函数:
template<typename ...Ts>
void xsys_vgui(const char *fmt, Ts ...args) {
sys_vgui(const_cast<char *>(fmt), args ...);
}
现在
xsys_vgui("wm deiconify .x%lx\n", x);
在C ++中应该“正常工作”。
答案 1 :(得分:2)
如果您真的知道sys_vgui
并没有使用传递的指针来修改某些内容,那么在实践中虽然没什么用,但还是不错的,因为这种假设就在您的脑海中。
在c++17中,您可以使用std::string::data
:
sys_vgui(std::string{"wm deiconify .x%lx\n"}.data(), x);
在此之前(在c++11和c++14中,您必须手动指定std::array
的大小(包括空终止符,但是如果错了,编译器可能仍然会抱怨)< / p>
sys_vgui(std::array<char, 20>{"wm deiconify .x%lx\n"}.data(), x);
答案 2 :(得分:2)
不要滥用const_cast
的意图(即使没有滥用它,也请尝试并设法避免这种意图)。
这很可怕,但是可能可以完成您想要的事情:您想要的API的模板版本,旨在制造必需的可变数组并在之后适当转发。对于实际上提供非常量数组或指针的调用者,它应该直接调用api。
#include <iostream>
#include <algorithm>
void do_function(char *ptr)
{
std::cout << __PRETTY_FUNCTION__ << '\n';
}
template<size_t N>
void do_function(const char (&ar)[N])
{
std::cout << __PRETTY_FUNCTION__ << '\n';
char inside[N];
std::copy(ar, ar+N, inside);
do_function(inside+0);
}
int main()
{
char msg[] = "array test";
do_function(msg);
do_function("Something const");
do_function("Nothing");
}
输出
void do_function(char *)
void do_function(const char (&)[N]) [N = 16]
void do_function(char *)
void do_function(const char (&)[N]) [N = 8]
void do_function(char *)
注意:我并没有真正通过绞拧器,但是它会可能达到您的期望。最大的好处是您无需更改任何先前的通话(除了消除那些const_cast
错误的名词之外)。传递字符串文字的原始调用将仅开始工作。您只需要挂起模板版本,然后让编译器整理其余的版本即可。
答案 3 :(得分:1)
如果您不想更改sys_vgui
,则可以进行包装:
template<typename... Args>
void sys_vgui_c(char const *fmt, Args&&... args)
{
sys_vgui( const_cast<char *>(fmt), args... );
}
,然后使用字符串文字sys_vgui_c("wm deiconify .x%lx\n", x);
答案 4 :(得分:1)
可变参数宏如何?
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#define my_vgui(fmt_,...) \
do { \
char myfmt[strlen(fmt_) + 1]; \
strcpy(myfmt,fmt_); \
sys_vgui(myfmt,##__VA_ARGS__); \
} while (0)
void
sys_vgui(char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
fmt[0] |= 0;
vprintf(fmt,ap);
va_end(ap);
}
int
main(void)
{
my_vgui("hello\n");
my_vgui("hello %s\n","world");
return 0;
}
请注意,执行宏的方法可能更简洁,请参见:https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html