为什么可以将 const char* 分配给 char*?

问题描述 投票:0回答:5

我知道例如

"hello"
属于
const char*
类型。所以我的问题是:

  1. 我们如何将像

    "hello"
    这样的文字字符串分配给非
    const char*
    ,如下所示:

    char* s = "hello";  // "hello" is type of const char* and s is char*
                        // and we know that conversion from const char* to
                        // char* is invalid
    
  2. 是像

    "hello"
    这样的文字字符串,它会占用我所有程序中的内存,还是就像临时变量一样,在语句结束时会被销毁?

c++ string char literals
5个回答
24
投票

事实上,

"hello"
属于
char const[6]
类型。

但是问题的要点仍然是正确的 – 为什么 C++ 允许我们将只读内存位置分配给非

const
类型?

唯一的原因是向后兼容旧的 C 代码,而旧的 C 代码不知道

const
。如果 C++ 在这里严格的话,它会破坏很多现有的代码。

也就是说,大多数编译器都可以配置为对此类已弃用的代码发出警告,甚至默认这样做。此外,C++11 完全不允许这样做,但编译器可能还没有强制执行它。

对于Standerdese粉丝:

[参考 1]
C++03 标准:§4.2/2

非宽字符串文字的字符串文字 (2.13.4) 可以转换为“指向 char 的指针”类型的右值;宽字符串文字可以转换为“指向 wchar_t 的指针”类型的右值。无论哪种情况,结果都是指向数组第一个元素的指针。仅当存在显式适当的指针目标类型时才考虑此转换,而不是在一般需要从左值转换为右值时考虑。 [
注意:此转换已弃用

。参见附录 D。] 出于重载决策排序的目的 (13.3.3.1.1),此转换被视为数组到指针的转换,后跟限定转换 (4.4)。 [示例:“abc”作为数组到指针转换转换为“指向 const char 的指针”,然后作为限定转换转换为“指向 char 的指针”。 ]

C++11 只是删除了上面的引用,这意味着它在 C++11 中是非法代码。

[参考资料 2]

C99 标准 6.4.5/5“字符串文字 - 语义”:

在翻译阶段 7,值为零的字节或代码被附加到由一个或多个字符串文字产生的每个多字节字符序列。然后,使用多字节字符序列来初始化静态存储持续时间和长度足以包含该序列的数组。对于字符串文字,数组元素的类型为 char,并使用多字节字符序列的各个字节进行初始化;对于宽字符串文字,数组元素的类型为 wchar_t,并使用宽字符序列进行初始化...

未指定这些数组是否不同,只要它们的元素具有适当的值即可。

如果程序尝试修改此类数组,则行为未定义。


2
投票
是像
    "hello"
  1. 这样的文字字符串,它将占用我所有程序中的内存,还是就像临时变量一样,在语句结束时会被销毁?
    
    
它保存在程序数据中,因此在程序的生命周期内可用。您可以从当前范围返回对此数据的指针和引用。

const char*

转换为

char*
的唯一原因是与 C 的兼容性,例如 WinAPI 系统调用。与任何其他 const 转换不同,此转换是不明确的。
    


1
投票
string


std::string s("hello");

这就是 C++ 的方式。如果您确实必须使用 
char

,则需要创建一个数组并将内容复制到其上。

    


1
投票
s

作为指向字符的指针类型存储在RAM中。如果它是全局的或静态的,它会在堆上分配并在运行程序的生命周期中保留在那里。如果它是本地(“自动”)变量,则会在堆栈上分配它并保留在那里,直到当前函数返回。无论哪种情况,它都会占用保存指针所需的内存量。


字符串

"Hello"

是一个常量,它与所有其他常量和初始值设定项一起存储为程序本身的一部分。如果您构建的程序在设备上运行,则该字符串将存储在 ROM 中。


请注意,由于字符串是常量,并且

s

是指针,因此不需要复制。指针

s
只是指向存储字符串的位置。
    


-3
投票
std::string(const char *)

构造函数(实际上它更复杂,但没关系)。并且,类似地, char * (如果它是类型而不是指向类型的指针)可以有一个 const char * 构造函数,它正在复制内存。


我实际上不知道编译器在这里是如何工作的,但我认为它可能与我上面描述的类似:在堆栈中构造

"Hello"

的副本,并使用此副本的地址初始化

s
    

© www.soinside.com 2019 - 2024. All rights reserved.