简体   繁体   English

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

[英]Assigning string literal to char*: const_cast<char *> vs using char array

I'm using some C functions in my C++ environment. 我在C ++环境中使用了一些C函数。 And I get the following warnings because C++ doesn't allow assigning string literal to char * type. 而且我收到以下警告,因为C ++不允许将字符串文字分配给char *类型。

C++11 does not allow conversion from string literal to char * C ++ 11不允许从字符串文字转换为char *

My Code: 我的代码:

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);
}

And I could remove these warnings by const casting the string literals as the following. 并且我可以通过const强制转换字符串文字来删除这些警告,如下所示。

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);

But I'm not sure if it's really safe as I've seen many people saying not to directly cast string literal to char * . 但是我不确定它是否真的安全,因为我已经看到很多人说不要直接将字符串文字转换为char *

So I came up with the following which seems like a safer solution. 因此,我提出了以下似乎更安全的解决方案。

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);

But it makes my code dirty and harder to maintain as I have to create multiple variables using different names(eg str1, str2, str3...) whenever I use the function. 但是,这使我的代码变得肮脏且难以维护,因为每当我使用该函数时,都必须使用不同的名称(例如str1,str2,str3 ...)创建多个变量。

So my questions are: 所以我的问题是:

1) Is it really not safe to use const_cast<char *> in my case? 1)在我的情况下使用const_cast<char *>真的不安全吗?

2) Any solution to write a clean code using char arrays without having to create multiple variables using different names? 2)有什么解决方案可以使用char数组编写干净的代码,而不必使用不同的名称创建多个变量?

It is safe as long as sys_vgui does not modify the string, which presumably it doesn't because modifying a string literal has undefined behavior in C, const or not. 只要sys_vgui不修改字符串是安全的,这大概不是因为修改字符串文字在C中具有未定义的行为(无论是否为const So if you have something like 所以如果你有类似的东西

sys_vgui("wm deiconify .x%lx\n", x);

in C, then the C++ version with const_cast is just as safe. 在C语言中,带有const_cast的C ++版本同样安全。

However, to de-uglify the C++ code, I'd probably write a wrapper function: 但是,为了消除C ++代码的丑陋程度,我可能会编写一个包装函数:

template<typename ...Ts>
void xsys_vgui(const char *fmt, Ts ...args) {
    sys_vgui(const_cast<char *>(fmt), args ...);
}

Now 现在

xsys_vgui("wm deiconify .x%lx\n", x);

should "just work" in C++. 应该在C ++中“正常工作”。

If you really know that sys_vgui doesn't use the passed pointer to modify something, it's fine in practice, although dirty, because that assumption is just in your head. 如果您真的知道sys_vgui不使用传递的指针来修改某些内容,那么这在实践中是可以的,尽管很脏,因为这种假设就在您的脑海中。

In you can use std::string::data : 您可以使用std::string::data

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

Prior to that (in and ) you have to specify the size manually to std::array (including null terminator, but the compiler will probably complain anyway if it's wrong) 在此之前(在 ),您必须手动指定std::array的大小(包括空终止符,但是如果错了,编译器可能仍然会抱怨)

sys_vgui(std::array<char, 20>{"wm deiconify .x%lx\n"}.data(), x);

Don't abuse the const_cast intentions (and even if not abusing it, try and contrive a way to avoid it in the first place). 不要滥用const_cast意图(即使不滥用它,也请尝试并设法避免这种情况)。

This is rather hideous, but may do what you intend: a template version of the API you desire, designed to manufacture the requisite mutable array and forward it appropriately thereafter. 这是相当丑陋的,但是可以按照您的意图进行:您想要的API的模板版本,用于制造必需的可变数组并在之后适当转发。 For callers actually supplying non-const arrays or pointers, it should just invoke the api directly. 对于实际上提供非常量数组或指针的调用者,它应仅直接调用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");
}

Output 输出量

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 *)

Note: I've not really put this through the wringer, but it will likely achieve what you desire. 注意:我并没有真正解决这个问题,但是它可能会达到您的期望。 This biggest bonus is you need not change any of the prior calls (beyond removing those const_cast misnomers). 最大的好处是您不需要更改任何先前的调用(除了删除那些const_cast错误的名词)。 the original calls passing string literals will simply start working. 传递字符串文字的原始调用将仅开始工作。 All you need to is hang the template version and let the compiler sort out the rest. 您只需要挂起模板版本,然后让编译器整理其余的代码即可。

If you do not want to change sys_vgui then you can make a wrapper: 如果您不想更改sys_vgui则可以进行包装:

template<typename... Args>
void sys_vgui_c(char const *fmt, Args&&... args)
{
     sys_vgui( const_cast<char *>(fmt), args... );
}

and then call it with the string literal: sys_vgui_c("wm deiconify .x%lx\\n", x); 然后使用字符串文字对其进行调用: sys_vgui_c("wm deiconify .x%lx\\n", x);

How about a variadic macro: 可变参数宏如何:

#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;
}

Note that there may be cleaner ways to do the macro, so see: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html 请注意,执行宏的方法可能更简洁,请参见: https//gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM