二进制字面量

1. 基本语法

C++14 引入了二进制字面量,允许开发者直接使用二进制数字表示整数,使代码在涉及位操作时更加直观和可读。

下面是基本语法格式:

1
2
int a = 0b101010;        // 二进制前缀 0b, 十进制的 42
int b = 0B11110000; // 大写 B 也可以

二进制数 0b101010 每一位的权值从右向左依次是 20,21,22,…

二进制数 0B11110000 每一位的权值从右向左依次是 20,21,22,…

我们可以通过代码将指定的二进制数值以十进制的格式进行输出,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <bitset>

int main()
{
// 二进制字面量
int binary1 = 0b1010; // 十进制 10
int binary2 = 0b11110000; // 十进制 240
int binary3 = 0b100000000; // 十进制 256

std::cout << "0b1010 = " << binary1 << std::endl;
std::cout << "0b11110000 = " << binary2 << std::endl;
std::cout << "0b100000000 = " << binary3 << std::endl;

return 0;
}

2. 其它字面量修饰符

2.1 有符号/无符号

在C++14 中二进制字面量还可以配合有符号/无符号修饰符使用:

1
2
3
unsigned int a = 0b1010u;      // 无符号
unsigned long b = 0b1010ul; // 无符号长整型
long long c = 0b1010ll; // 长长整型
  • uunsigned
  • ulunsigned long
  • lllong long

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <type_traits>

int main()
{
auto x = 0b1010u; // unsigned int
auto y = 0b1010ul; // unsigned long
auto z = 0b1010ull; // unsigned long long

std::cout << "Type of 0b1010u: " << typeid(x).name() << std::endl;
std::cout << "Type of 0b1010ul: " << typeid(y).name() << std::endl;
std::cout << "Type of 0b1010ull: " << typeid(z).name() << std::endl;

return 0;
}

2.2 数值分割符

C++14 还引入了数字分隔符 ‘(即单引号),可以与二进制字面量结合使用,这样可以提供可读性(不影响数值):

1
2
int a = 0b1001'0011'1010'0101;  // 使用单引号 ' 作为分隔符
int b = 0b1111'0000'1100'0011;

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

int main()
{
// 使用分隔符提高可读性
int mask1 = 0b1111'0000; // 更容易看出是 F0
int mask2 = 0b1000'0000'0000'0000; // 高位掩码
int flags = 0b0010'0101; // 多个标志位

std::cout << "掩码1: " << std::hex << mask1 << std::endl;
std::cout << "掩码2: " << std::hex << mask2 << std::endl;
std::cout << "标志位: " << std::hex << flags << std::endl;

return 0;
}

数值分割符除了在二进制数据中使用,也可以在其它进制的数值中使用,比如:

1
2
3
4
5
6
long long bigNumber = 1'000'000'000;     // 长整形, 10进制
double pi = 3.14159'26535'89793; // 浮点型, 10进制
int hex = 0xFF'FF'FF'FF; // 16进制
int binary = 0b1000'0001'1000'0000; // 2进制
int octal1 = 012'345; // 八进制 12345 = 十进制 5349
int octal2 = 07'77'777; // 八进制 777777 = 十进制 262143

语法规则总结:

  1. 允许的用法

    1
    2
    3
    int a = 012'345;      // ✅ 正确:分隔3位数字
    int b = 0'123'456; // ✅ 正确:分隔任意位置
    int c = 07'654'321; // ✅ 正确:分隔符提高可读性
  2. 不允许的用法

    1
    2
    3
    int d = '12345;      // ❌ 错误:不能在第一个数字之前
    int e = 12345'; // ❌ 错误:不能在数字结尾
    int f = 12''345; // ❌ 错误:不能连续使用分隔符

3. 实际应用场景

3.1 位掩码和标志位

下面的代码中展示了如何使用位标志位(bit flags)来管理文件权限,这是一个非常经典的用法:

  1. 使用二进制字面量0b001 是 C++14 引入的二进制字面量,清晰易读
  2. 枚举定义FilePermissions 枚举定义了三个权限标志
  3. 位运算:使用 & 运算符检查是否设置了特定权限位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

// 定义标志位
enum FilePermissions
{
READ = 0b001,
WRITE = 0b010,
EXECUTE = 0b100
};

int main()
{
// 设置权限
int user_perms = 0b111; // 读、写、执行
int group_perms = 0b101; // 读、执行
int other_perms = 0b001; // 只读

// 检查权限
if (user_perms & FilePermissions::WRITE)
{
std::cout << "用户有写权限" << std::endl;
}

return 0;
}

3.2 颜色处理

下面的代码中展示了 位运算 在颜色处理中的经典应用,主要目的是将ARGB(Alpha, Red, Green, Blue)四个8位分量打包成一个32位整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <iomanip>

// ARGB 颜色格式
struct Color
{
unsigned int argb;

Color(unsigned char a, unsigned char r,
unsigned char g, unsigned char b)
{
argb = (a << 24) | (r << 16) | (g << 8) | b;
}

// 提取Alpha分量
unsigned char getAlpha() const
{
return (argb & ALPHA_MASK) >> 24;
// 或者更简单:return argb >> 24;
}

// 提取Red分量
unsigned char getRed() const
{
return (argb & RED_MASK) >> 16;
}

void print() const
{
std::cout << "ARGB: 0x" << std::hex << std::setfill('0')
<< std::setw(8) << argb << std::endl;
}
};

int main()
{
// 使用二进制字面量定义颜色掩码
constexpr unsigned int ALPHA_MASK = 0b1111'1111'0000'0000'0000'0000'0000'0000;
constexpr unsigned int RED_MASK = 0b0000'0000'1111'1111'0000'0000'0000'0000;
constexpr unsigned int GREEN_MASK = 0b0000'0000'0000'0000'1111'1111'0000'0000;
constexpr unsigned int BLUE_MASK = 0b0000'0000'0000'0000'0000'0000'1111'1111;

Color red(255, 255, 0, 0);
red.print();

return 0;
}

关于Color 结构体的成员:

  • A (Alpha):透明度(0-255,0完全透明,255完全不透明)
  • R (Red):红色分量
  • G (Green):绿色分量
  • B (Blue):蓝色分量
  • 每个分量都是8位(0-255),总共32位

构造函数 - 位运算打包:

1
argb = (a << 24) | (r << 16) | (g << 8) | b;

内存布局(32位 = 4字节):

1
2
3
字节3     字节2     字节1     字节0
[Alpha] [Red] [Green] [Blue]
0xFF 0xFF 0x00 0x00 // 红色不透明

位运算分解

  • a << 24:Alpha值左移24位 → 占据最高8位(位31-24)
  • r << 16:Red值左移16位 → 占据次高8位(位23-16)
  • g << 8:Green值左移8位 → 占据中间8位(位15-8)
  • b:Blue值不移动 → 占据最低8位(位7-0)
  • |(按位或):将四个部分合并

掩码定义:二进制字面量

1
constexpr unsigned int ALPHA_MASK = 0b1111'1111'0000'0000'0000'0000'0000'0000;
  • 0b前缀:C++14引入的二进制字面量
  • '分隔符:提高可读性(每8位一组)
  • 常量表达式:constexpr 编译期常量
  • ALPHA_MASK:0xFF000000(提取Alpha分量)
  • RED_MASK:0x00FF0000(提取Red分量)
  • 可用于提取颜色分量:alpha = (argb & ALPHA_MASK) >> 24

4. 总结

综上所述,关于C++14 的二进制字面量的特性可以做如下总结:

  • 提高代码可读性:在位操作场景中更直观
  • 配合分隔符' 分隔符使长二进制数更易读
  • 编译时友好:支持编译时计算和常量表达式
  • 类型灵活:可与各种整数类型修饰符结合使用

在进行项目开发是时候可以灵活使用,这个特性特别适合如下应用场景:

  • 嵌入式开发(寄存器操作)
  • 网络编程(协议标志位)
  • 图形编程(颜色处理)
  • 加密算法(位操作密集)
  • 系统编程(权限控制)