C++14的整数字面值(10进制、8进制、2进制数,有无符号,类型的声明)

字面常量表示我们直接写出来的常量值,所见即所得,不具有名称,是纯粹的右值(prvalue)。C++14的标准在C++11的标准上增加了两个让人有那么点小兴奋的特性:1.二进制数定义,2.数位分隔。这两个特性在VS2015中已经可以使用,但是在g++5.3.0还不行。接下来详细地说明。


二进制字面值

二进制字面值可以使用0b或者0B开头来表示,比如:

int i = 0b0100010001;  // 273
int i = 0B0100010001;  // 273,大写B

数位分隔符

可能就是因为提出了2进制数的表示,但是2进制数很冗长,怎么好看点呢?就提出了数位分隔符。我自己这样猜的^_^。数位分隔符不仅可以用在2进制数中,也可以用在8进制,10进制和16进制数中。上面的二进制数不好看,可以4位一个分隔符

int i = 0b01'0001'0001;  // 273

再说10进制数按千位分隔

long k = 1'234'567'890
这样看起来好多了。


无符号声明

无符号字面值可以帮我们强制指定一个字面常量是一个无符号数,通过在字面值后面加上“u”或“U”来指定,例如:

int bin1 = 0b0001'0001u; // 小u
int bin2 = 0b0001'0001U; // 大写u

无符号指定在C++98的标准里已经出现。虽然默认是有符号的,但是在VS2015中,当32位二进制数的最高位(最左边是最高位)是1时,会被自动识别为无符号数,因为如果是有符号数最高位为符号位,为1就是负数了。不知道g++的特性是不是这样,如果不是的话就体现出u修饰的作用了,强制将类型识别为无符号。


类型声明
类型声明在C++98的标准里也已经出现,但是在C++11之后,又补充了指定超长整型的说明符ll和LL,对应类型long long。例如

int m = 0b0100'0001LL; // 超长整形的字面值

但是在VS2015里,只要数值不超过变量的范围,就不会出现截断警告。实际上,如果数值小于int的范围,类型就是int (标准原文:If an integer literal cannot be represented by any type in its list and an extended integer type (3.9.1) can represent its value, it may have that extended integer type.) 。如果超过int,在long的范围内就是long,long超过就是long long。也就是说就算不加类型声明符也能自动识别类型。另外,标准还有一句话:当值不能用已有的整型类型表示时就是错误的 (标准原文:A program is ill-formed if one of its translation units contains an integer literal that cannot be represented by any of the allowed types) ,比如说:

int bin = 0X1'0000'0001'0001'0001'1000'0001'0001'0001LL; // 错误的字面值,过大,连long long都超过了

如何阅读标准的定义

整数字面值的的定义在标准的2.14.2 节Integer literals中规定,下面给出标准中对整数字面值的描述:


有没想到整数字面值的定义如此之长吧。实际上要看也很简单,顶格的行称为非终结符,也就是说出现这个名称的时候,这个名称其实还代表别的东西,要看后面这个名称具体可以代表什么。这些名称一般都是望文生义的。比如一开始的integer-literal,就代表着全部的整数字面值的定义都从这里开始。

缩进两格的是非终结符的定义,定义可以还是用非终结符来描述,也可以用终结符,甚至是混合来描述。终结符就是不可再推导的符号,自己代表自己,上图中的'、0、0x、0X、0b、0B、1到9、a到f、A到F、u、U、l、L、ll、LL就是终结符。

这时候我们就能来解读一下integer-literal,有4种定义(一行一个),也就是说这四种定义规定的表达,都是整数字面值。

第一种是decimal-literal integer-suffixopt,由两部分组成。中间空格只是分开单词用的,实际上两部分是直接接在一起的。第一部分是decimal-literal,去看它的定义:

nonzero-digit
decimal-literal ’opt digit

一种是nonzero-digit,非0数值,就是1到9,这里的nonzero-digit指的是单个数字,那么多个数字的比如123这样的是怎么定义的呢?就是第二种decimal-literal ’opt digit,其中右下角的opt表示'是可选的,这就是C++14的数位分隔,可以用'分隔数位。可以发现第二种形式是递归的,开头还是decimal-literal,最后一定是digit,也就是0到9。所以decimal-literal可以写成decimal-literal ’opt digit还可以继续推导成decimal-literal ’opt digit ……’opt digit,这样无限的数位不就出来了吗。而且要停止递归,最终decimal-literal只能推导成nonzero-digit。这个推导表明,10进制数的开头不能是0,分隔符'可以出现在任意的数位之间,却不能出现在最开头,显然这就是我们一直在用的10进制数的定义,除了分隔符'。

第二部分是integer-suffixopt,opt说明这是一个可以省略的部分,望文生义是整数后缀。看它的定义是

unsigned-suffix long-suffixopt
unsigned-suffix long-long-suffixopt
long-suffix unsigned-suffixopt
long-long-suffix unsigned-suffixopt

可以发现总共就是三个非终结符,分别是unsigned-suffix、long-suffix、long-long-suffix,分别是无符号声明和显式的long类型声明、显式的long long类型声明。四种形式传达了三个信息:

1.无符号声明和显式类型声明的相对位置没有限制

2.显式long类型声明和显式long long类型声明不共存

3.无符号声明和显式类型声明可以共存,也可以不共存

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值