将字符串文字分配给char *:const_cast <char * =“”>与使用char数组

时间:2018-07-10 03:11:26

标签: c++ string casting

我在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数组编写干净的代码,而不必使用不同的名称创建多个变量?

5 个答案:

答案 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并没有使用传递的指针来修改某些内容,那么在实践中虽然没什么用,但还是不错的,因为这种假设就在您的脑海中。

中,您可以使用std::string::data

sys_vgui(std::string{"wm deiconify .x%lx\n"}.data(), x);

在此之前(在中,您必须手动指定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