/* 转载请注明出处:http://www.cnblogs.com/Martinium/p/binary_literal.html */


二进制的语法

  C/C++ 默认数字使用十进制,八进制使用前缀 0, 十六进制使用前缀 0x 或 0X,二进制常数的提议被否决(引用 C 语言程序原理国际标准 的 6.4.4.1 章节字段 "A proposal to add binary constants was rejected due to lack of precedent and insufficient utility."),一直没有二进制的表示方法, GCC 使用 0b/0B 前缀作为扩展,其实很多编译器都有这个扩展的,只是标准委员会一直没采纳。直到 C++14 才引进,可谓姗姗来迟啊。这种二进制语义 Java 7 也早些时候引入,Python 2.6 以及后来的 3 也引入,Python 为了避免十进制与八进制的混淆,一律用字母前缀,不分大小写,0b 为二进制,0o 为八进制,ox 为十六进制。Python2 升到 Python3 时果断丢弃了原来的八进制语义(也就是在 C/C++/Java 里面有 0 前缀的八进制的语义)。
 
表示方法
1. 下面每行语句表达语义相同,只是选用不同的进制数表示。
int i = 0b101010;  // binary
int i = ; // octal
int i = ; // decimal
int i = 0x2a; // hexadecimal
2. 使用 strtol/strtoll/strtoq 函数,可以将一个字符串转换成整数,base 取 2 表示转换成二进制数。
#include <stdlib.h>
long int strtol(const char *nptr, char **endptr, int base);
long long intstrtoll(const char *nptr, char **endptr, int base);

我在解密一些二进制数据的时候,用到过这个函数。先用正则表达式每八个数字一拆分 echo A_LONG_BINARY_STRING | sed -r 's/([01]{8})/\1 /g',然后利用空格作间隔符提取数字所代表的 ASCII 码,当然,你也可以用移位运算自己实现每八个数字一读的功能。

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h> int main()
{
const char* raw = "01110101 01110011 01100101 00100000 01110111 01100101 01100100 01101110 01100101 01110011 01100100 01100001 01111001 00100000 01100110 01101111 01110010 00100000 01110100 01101000 01100101 00100000 01100001 01101110 01110011 01110111 01100101 01110010";
const char* begin;
char* end = const_cast<char*>(raw);
do
{
begin = end;
long int byte = strtol(begin, &end, /*base*/);
putchar(static_cast<int>(byte));
}while(begin != end); return ;
}
3.  也可以使用 STL 里的 bitset 完成,不仅可以用数字,也可以用其他字符表示 0/1,这个比方法 2 更强大。这种方法我在做培根密码解密题用到过,将 A/B 字符映射成 0/1 数字。

// unsigned long long constructor
std::bitset<> ();
// string constructor
std::string bits = "";
std::bitset<> binary(bits); // [0,0,1,1,0,0,1,0]
// string constructor using custom zero/one digits
std::string bacon = "ABABB";
std::bitset<> m(bacon, , std::string::npos, 'A', 'B'); // [0,1,0,1,1]
 
4. 可以使用 boost 库的 BOOST_BINARY, 可以每隔开几个数字一写,在表示很大的数时很方便阅读。
int value1 = BOOST_BINARY(      );
unsigned long value2 = BOOST_BINARY_UL( ); // unsigned long
long long value3 = BOOST_BINARY_LL( ); // long long if supported

提到方便阅读,C++14 加入了数字分隔符这个想法, 于是可以写成 double e = 2.718'281'828'459'045'; 方便阅读。

5. 如果不是一项工程,而是简短的程序,可以利用 C++ 的模板模拟二进制语义。
template<unsigned long long N>
struct binary
{
enum { value = (N%) + binary<N/>::value* };
}; template<>
struct binary
{
enum { value = };
}
 
int value = static_cast<int>(binary<101010>::value);
上面的代码中, enum 是为了让变量在编译期获取结果,没有用整型。还有一个问题是如果数的开头有 0,结果可不妙。整个数被当成了八进制而不是十进制数解析,很容易滋生 bug。比较好的解决方法是数字经常以 0 开头(或添加断言强制),将十进制换成八进制。
 
 
// need to enable C++11 flag
template<unsigned long long>
struct binary
{
  constexpr static int value = binary<N/>::value + N%;
}; template<>
struct binary<>
{
  constexpr static int value = ;
}
6.  采用用户自定字面值(User-defined literals),注意这个是 C++11 新加的功能。之前的 C++03 内置一些类似的语义(比方说在浮点数后加字符 "f" 表示声明一个 float 而不是 double),但是用户不能自己定义。
C++11 开放用户定义新的字面修饰符(literal modifier),利用自定义的修饰符完成由字面值构造对象。所有的自定字面值必须是后置,前置是不允许的。C++11 开放用户定义新的字面修饰符(literal modifier),利用自定义的修饰符完成由字面值构造对象。除了下划线,所有的后置被标准保留。所以,用户定义时需要以下划线开头。
int operator "" _B(int i);
static_assert( 101010_B == 42);
 
 

C++ 的二进制语法与语义的更多相关文章

  1. assertion的语法和语义

    .1) 语法表示 在语法上,为了支持assertion,Java增加了一个关键字assert.它包括两种表达式,分别如下: assert expression1; assert expression1 ...

  2. 解读HTML 5新语法 提高语义价值

    HTML 5的新标记 设计者们需要完成的任务是要给HTML 5开发一个更丰富的和更有含义的语义,当然可以想象这种新方案将会是很灵活和很高效的,同时与所有的现代互联网标准相适应.下面就是一些将要在HTM ...

  3. Eigen与Matlab语法及语义辞典

    Eigen为Matlab转换为C++提供了一个简单的语法级别的代码迁移工具. 对一些代码进行了扩充,以便程序由Matlab到Eigen的移植................... 参考链接:http: ...

  4. HTML5经典实例——1基础语法和语义

    1指定DOCTYPE 在页面的最开始处指定HTML5 DOCTYPE DOCTYPE是不区分大小写的.可以任意的使用大小写. <!DOCTYPE html> <html lang=& ...

  5. 15.3 Task 语法和语义

    15.3.1 声明异步方法和返回类型 async static void GetStringAsync() { using (var client = new HttpClient()) { Task ...

  6. net-force.nl/steganography writeup

    做CTF题好长一段时间了,真的可以学到很多东西.这次,我们开启 net-force.nl 的 Steganography之旅,所谓的隐写术. level 801: Training - Can you ...

  7. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  8. Python3语法详解

    一.下载安装 1.1Python下载 Python官网:https://www.python.org/ 1.2Python安装 1.2.1 Linux 平台安装 以下为在Unix & Linu ...

  9. HTML标记语法之表格元素

    语法与语义: <table>和</table>定义表格的开始和结束 <thead>和</thead>定义表格头部的开始和结束 <tbody> ...

随机推荐

  1. ScrollView中嵌套recycleView 出现的不显示,显示不全,终极解决方案

    最近公司项目中用到了ScrollView去嵌套recycleView, 最开始我天真的把recycleView直接放入scrollView中,结果可想而知,什么都不显示,瞬间懵逼,我心想应该是和嵌套L ...

  2. 基于Spring4+Hibernate4的通用数据访问层+业务逻辑层(Dao层+Service层)设计与实现!

    基于泛型的依赖注入.当我们的项目中有很多的Model时,相应的Dao(DaoImpl),Service(ServiceImpl)也会增多. 而我们对这些Model的操作很多都是类似的,下面是我举出的一 ...

  3. 用php去除bom头

    最近在用dede开发一个网站的时候,发现网站在本地没什么问题,但是上传到服务器上面去之后,在首页会默认的生成一串的字符串,如下图所示: 百度了之后,发现好多的解决方法都是说的把文件存储为utf-8无 ...

  4. php-fpm中启用慢日志配置(用于检测执行较慢的PHP脚本)

    虽然通过nginx accesslog可以记录用户访问某个接口或者网页所消耗的时间,但是不能清晰地追踪到具体哪个位置或者说函数慢,所以通过php-fpm慢日志,slowlog设置可以让我们很好的看见哪 ...

  5. 09 Object

    Object 在看 ES6 Object的时候,我发觉ES5 Object 的更新我并不是完全知道. 于是觉得还是看一下. 1. __proto__ 作为一个 半吊子前端开发人员. 居然不知道这个.. ...

  6. 面试题目——《CC150》链表

    面试题2.1:编写代码,移除未排序链表中的重复结点 进阶:如果不得使用临时缓冲区,该怎么解决? package cc150; import java.util.HashMap; import java ...

  7. python中的IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

  8. 关于Visual Studio 2015中没有报表项(ReportViewer)的解决方案。

    没有报表,一般默认安装之后会出现这种情况,在安装的时候选择自定义安装,把Microsoft Office 开发人员工具.Microsoft SQL Server Data Tools勾选上,安装之后就 ...

  9. [UML]UML系列——类图class的实现关系Realization

    系列文章 [UML]UML系列——用例图Use Case       [UML]UML系列——用例图中的各种关系(include.extend)       [UML]UML系列——类图Class   ...

  10. Node.js与Express4安装与配置

    Nodejs简介 Node.js 基于 Chrome JavaScript 运行环境,用于便捷地搭建快速.可扩展的网络应用. 它使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效, 非常适合 ...