令我惊讶的是,它汇编为:
const char* c_str()
{
static const char nullchar = '\0';
return nullchar;
}
并且在我的代码中引入了一个错误。幸运的是,我抓住了它。
这是C ++故意还是编译器错误?是否有理由主动忽略数据类型?
它可以在Visual C ++ 2010和GCC中工作,但是鉴于明显的数据类型不匹配,我不明白为什么它应该工作。(static
也没有必要。)
令我惊讶的是,它汇编为:
const char* c_str()
{
static const char nullchar = '\0';
return nullchar;
}
并且在我的代码中引入了一个错误。幸运的是,我抓住了它。
这是C ++故意还是编译器错误?是否有理由主动忽略数据类型?
它可以在Visual C ++ 2010和GCC中工作,但是鉴于明显的数据类型不匹配,我不明白为什么它应该工作。(static
也没有必要。)
constexpr
是++ 11-特定的C反正...但const
变量是由C ++ 03标准...的§5.19.1常量表达式的积分常数表达式可以只涉及文字(2.13),统计员,const
使用常数表达式(8.5)初始化的整数或枚举类型的变量或静态数据成员,整数或枚举类型的非类型模板参数以及sizeof
表达式。
Answers:
如您所定义,它nullchar
是一个整数常量表达式,其值为0。
C ++ 03标准将空指针常量定义为:“空指针常量是整数类型的整数常量表达式(5.19)rvalue,其值为零。” 长话短说,yournullchar
是一个空指针常量,这意味着它可以隐式转换并分配给基本上任何指针。
请注意,所有这些元素都是使隐式转换正常运行所必需的。例如,如果您使用'\1'
而不是'\0'
,或者您未指定的const
限定词nullchar
,那么您将无法获得隐式转换-您的分配将会失败。
包含此转换是有意的,但众所周知。0为空指针常量,是从C继承的。我相当确定Bjarne和大多数C ++标准委员会(以及大多数C ++社区)将非常希望删除此特定的隐式转换,但是这样做会破坏与许多C代码的兼容性(可能接近所有C代码)。
const
具有值的变量0
不能视为空指针常量,这意味着OP的代码在C中无效(因此,不会因任何更改而“中断”,因为它已中断从C的角度来看)。
bool
。在C语言中,它通过与文字的隐式比较来工作0
,即if (p)
等于if (p != 0)
。后者也不使用转换为int
。
这是一个古老的历史:它可以追溯到C。
null
C中没有关键字。C中的空指针常量是:
0
,0L
,'\0'
(记住,char
是整体型),(2-4/2)
void*
,如(void*)0
,(void*)0L
,(void*)'\0'
,(void*)(2-4/2)
该NULL
宏(不是关键字!)扩展到这样的空指针常量。
在第一个C ++设计中,仅允许将整数常量表达式用作空指针常量。最近std::nullptr_t
被添加到C ++。
在C ++中,但在C中不是,const
用整数常量表达式初始化的整数类型变量是整数常量表达式:
const int c = 3;
int i;
switch(i) {
case c: // valid C++
// but invalid C!
}
因此const char
,使用表达式初始化的'\0'
是一个空指针常量:
int zero() { return 0; }
void foo() {
const char k0 = '\0',
k1 = 1,
c = zero();
int *pi;
pi = k0; // OK (constant expression, value 0)
pi = k1; // error (value 1)
pi = c; // error (not a constant expression)
}
而且您认为这不是声音设计吗?
已更新,以包括C99标准的相关部分...根据§6.6.6...
一个整数常量表达式应具有整数型和应仅具有是积分常数,枚举常数,字符常数,操作数
sizeof
表达式,其结果是积分常数,和浮动是铸件的立即操作数的常量。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为sizeof
运算符的一部分。
对于纯C ++程序员的一些说明:
sizeof
始终是一个编译时间常数。但是C具有可变长度的数组,因此sizeof
有时不是编译时间常数。然后,我们看到§6.3.2.3.3状态...
值为0的整数常量表达式或转换为类型的表达式
void *
称为空指针常量。如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针)将不等于与任何对象或函数的指针进行比较。
要了解此功能的年代久远,请参阅C99标准中相同的镜像部件...
第6.6.6节
一个整数常量表达式应具有整数型和应仅具有是积分常数,枚举常数,字符常数,操作数
sizeof
表达式,其结果是积分常数,和浮动是铸件的立即操作数的常量。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为操作数的一部分。sizeof
运算符的一部分。
§6.3.2.3.3
值为0的整数常量表达式或转换为类型的表达式
void *
称为空指针常量。如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针)将不等于与任何对象或函数的指针进行比较。
nullchar
是一个(编译时)常量表达式,值为0。因此,对于隐式转换为null指针来说,这是一个公平的游戏。
更详细地说:我在这里引用1996年标准草案。
char
是整数类型。 nullchar
是const,所以它是一个(编译时)整数常量表达式,如5.19.1节所述:
5.19常数表达式[expr.const]
1在某些地方,C ++要求表达式的计算结果为整数或枚举常量...整数常量表达式可能涉及... const变量...
此外,nullchar
根据第4.10.1节,计算结果为0,允许将其隐式转换为指针:
4.10指针转换[conv.ptr]
1整数类型的整数常量表达式(expr.const)的右值为0(称为空指针常量),可以转换为指针类型。
可能的一个直观原因“为什么”(就在我头顶)是未指定指针宽度,因此允许从任何大小的整数常量表达式转换为空指针。
已更新(较新的)C ++ 03标准的相关部分...根据§5.19.1...
一个积分常数表达式可以只涉及文字(2.13),统计员,
const
变量或常量表达式(8.5),积分或枚举类型的非类型模板参数,并初始化积分或枚举类型的静态数据成员sizeof
表达式。
然后,我们来看§4.10.1...
甲空指针常数是整数表达式(5.19)的整数类型的计算结果为零的右值。空指针常量可以转换为指针类型。结果是该类型的空指针值,并且可以与指向对象的指针或指向函数类型的指针的每个其他值区分开。相同类型的两个空指针值应比较相等。
static const char nullchar = '\x30'
或任何其他值,则编译确实会失败。因此Managu是正确的:0是特例。如果要在gcc中发出警告,请-Wconversion
在命令行上使用,它会在所有未明确使用强制转换的转换中发出警告。不确定MSVC。
g++ -std=c98 -pedantic -W -Wall
……您会看到它是标准的定义明确的部分:-)
出于与编译相同的原因进行编译
const char *p = 0; // OK
const int i = 0;
double *q = i; // OK
const short s = 0;
long *r = s; // OK
右侧的表达式具有类型int
和short
,而要初始化的对象是一个指针。这会让您感到惊讶吗?
在C ++语言(以及C语言)中,带值的整数常量表达式(ICE) 0
具有特殊的状态(尽管ICE在C和C ++中的定义不同)。它们符合空指针常量。在指针上下文中使用它们时,它们将隐式转换为适当类型的空指针。
类型char
是整数类型,int
在这种情况下没有太大区别,因此const char
初始化对象0
也是C ++中的空指针常量(但在C中不是)。
顺便说一句,bool
C ++中的类型也是整数类型,这意味着const bool
由初始化的对象false
也是空指针常量
const bool b = false;
float *t = b; // OK
后来针对C ++ 11的缺陷报告已更改了空指针常量的定义。校正之后,空指针常量只能是“值为零的整数文字或std :: nullptr_t类型的prvalue”。更正后,以上指针初始化在C ++ 11中不再具有良好的格式。
它不会忽略数据类型。这不是错误。它利用了您在其中放置的const的优势,并看到它的值实际上是整数0(char是整数类型)。
整数0是有效的(按定义)空指针常量,可以将其转换为指针类型(成为空指针)。
您希望空指针的原因是具有一些“指向无处”并且可以检查的指针值(即,您可以将空指针与整数0进行比较,并且返回true)。
如果删除const,则会出现错误。如果将double放入其中(与其他许多非整数类型一样;我想例外是只能通过[转换运算符的重载]转换为const char *的类型),您将得到一个错误(甚至是w / o const)。依此类推。
整个问题是,在这种情况下,您的实现看到您正在返回一个空的ptr常量;您可以将其转换为指针类型。
看来,这个问题的许多真正答案已经在评论中结束了。总结一下:
C ++标准允许const
将整数类型的变量视为“整数常量表达式”。为什么?很有可能绕过C仅允许宏和枚举保留整数常量表达式的位置的问题。
至少可以追溯到C89,值为0的整数常量表达式可以隐式转换为(任何类型的)空指针。这也是C代码,其中经常使用的NULL
是经常#define
“d作为(void*)0
。
回到K&R,文字值0
已用于表示空指针。该约定在各处使用,其代码如下:
if ((ptr=malloc(...)) {...} else {/* error */}
char *
,因此在const
引入时允许有问题的赋值是合理的。我不确定是否可以在K&R本身中阅读此通知。
有一个自动演员表。如果运行良好,请执行以下操作:
#include <stdio.h>
const char* c_str()
{
static const char nullchar = '\0';
return nullchar;
}
int main()
{
printf("%d" , sizeof(c_str()));
return 0;
}
输出在我的计算机上应该是4->指针的大小。
编译器自动转换。注意,至少gcc会发出警告(我不知道VS)