第二十五章:嵌入式系统程序设计 习题答案
- 本章习题所用到的头文件和实现
- Pool.h
- Stack.h
- 25.2
- 25.3
- 25.4 Calculator
- 25.5 and 25.6 较难发现的无限循环
- 25.7
- 25.8
- 25.9
- 25.10 and 25.11 位域,无符号数位运算,bitset<>
- 25.12
- 25.14 Vector, Pool 作为分配器
- 25.15 测试 new / delete, Pool, Stack 的分配与释放速度
本章习题所用到的头文件和实现
Pool.h
实现了两个版本的Pool,一个用标记数组跟踪已分配和未分配对象空间,另一个用链表跟踪
#include <list>
using namespace std;
//v1 Pool,用数组和索引跟踪已分配和未分配对象,
//分配速度如果是顺序分配则较快,若随机分配则有些慢
//释放速度快,额外空间占用小
template<typename T, int N>
class Pool_v1
{
size_t sz; //存储池总数量
size_t un_alloc; //未分配的对象的数量
size_t luai; //内存地址最小的未分配的对象的索引 least unallocated index
T* space; //内存空间,N个T对象
bool is_alloc[N]; //表明哪个已分配,哪个未分配
public:
Pool_v1(); //创建N个T的存储池
T* get(); //从存储池获取一个T,若无空闲T则返回0
void free(T*); //将get()获得的一个T归还存储池
int available() const //空闲T的数目
{
return un_alloc;
}
};
template<typename T, int N>
Pool_v1<T,N>::Pool_v1()
:sz{ N }, un_alloc{ N }, luai{ 0 }, space{ new T[N] }
{
for (size_t i = 0; i < N; ++i)
is_alloc[i] = false;
}
template<typename T, int N>
T* Pool_v1<T, N>::get()
{
if (un_alloc == 0)
return 0;
//先确定要返回的对象地址
size_t index = luai;
is_alloc[index] = true;
--un_alloc;
//下面寻找下一个未分配的对象
if (un_alloc == 0)
luai = sz; //如果都分配满了,那么就把它设置为最后的索引之后的位置
else
for (size_t i = luai + 1; i < sz; ++i)
if (!is_alloc[i])
{
luai = i;
break;
}
return &space[index];
}
template<typename T, int N>
void Pool_v1<T, N>::free(T* obj)
{
*obj = T{}; //将归还的对象设置为默认值
++un_alloc;
size_t index = obj - space; //释放位置的索引
if (index < luai)
luai = index;
is_alloc[index] = false;
}
//------------------------------------------------------------------
//v2 Pool,用链表跟踪已分配和未分配对象,
//分配速度若顺序分配慢于Pool_v1,随机分配可能会快一些,
//释放速度慢,且额外空间占用大
//需要一个专用于Pool的list,其insert和erase操作不进行动态内存分配和释放
template<typename T>
struct Node
{
T val;
Node* pred;
Node* succ;
};
template<typename T>
class List_for_pool
{
Node<T>* header;
size_t sz;
public:
class iterator;
List_for_pool();
~List_for_pool();
iterator begin() { return iterator{ header->succ }; }
iterator end() { return iterator{ header }; }
//以下的加入和移除元素,都不释放节点
iterator insert(iterator p, Node<T>* pn); //将节点 n 插入链表中 p 之后的位置
iterator erase(iterator p); //从链表中删除p
//以下加入和删除元素,会动态分配内存
void push_back(const T& v);
size_t size() const { return sz; }
};
template<typename T>
class List_for_pool<T>::iterator
{
Node<T>* curr;
public:
iterator(Node<T>* p) :curr{ p } { }
iterator& operator++() { curr = curr->succ; return *this; }
T& operator*() { return curr->val; }
bool operator==(const iterator& b) const { return curr == b.curr; }
bool operator!=(const iterator& b) const { return curr != b.curr; }
Node<T>* get_pnode() { return curr; } //用于直接获得节点指针
};
template <typename T>
List_for_pool<T>::List_for_pool()
:header{ new Node<T>{T{},nullptr,nullptr} }, sz{ 0 }
{
header->succ = header->pred = header;
}
template <typename T>
List_for_pool<T>::~List_for_pool()
{
Node<T>* p;
for (p = header->succ; p != header;)
{
Node<T>* temp = p;
p = p->succ;
delete temp;
}
delete header;
}
template <typename T>
typename List_for_pool<T>::iterator List_for_pool<T>::insert(iterator p, Node<T>* pn)
{
//将节点 n 插到 p 的前面,不释放节点
Node<T>* temp = p.get_pnode();
pn->pred = temp;
pn->succ = temp->succ;
temp->succ->pred = pn; //因为是循环链表,不用检查是否为空
temp->succ = pn;
++sz;
return iterator{ pn };
}
template <typename T>
typename List_for_pool<T>::iterator List_for_pool<T>::erase(iterator p)
{
//将 p 位置节点删除,不释放节点
if (begin() == end())
return end();
if (p == end())
return end();
Node<T>* np = p.get_pnode();
Node<T>* q = np->succ;
q->pred = np->pred;
np->pred->succ = q;
--sz;
return iterator{ q };
}
template <typename T>
void List_for_pool<T>::push_back(const T& v)
{
//在链表末尾插入元素,新建节点(需要动态内存分配)
Node<T>* pnode = new Node<T>;
pnode->val = v;
header->pred->succ = pnode;
pnode->succ = header;
pnode->pred = header->pred;
header->pred = pnode;
++sz;
}
template<typename T, int N>
class Pool_v2
{
size_t sz; //存储池总数量
T* space; //内存空间,N个T对象
List_for_pool<T*> lst_unalloc; //链表元素指向空闲对象
List_for_pool<T*> lst_alloc; //链表元素指向已分配对象
//设置已分配链表的目的是为了防止重复创建节点
//创建节点会调用动态内存分配
public:
Pool_v2(); //创建N个T的存储池
T* get(); //从存储池获取一个T,若无空闲T则返回0
void free(T*); //将get()获得的一个T归还存储池
int available() const //空闲T的数目
{
return lst_unalloc.size();
}
~Pool_v2();
};
template<typename T, int N>
Pool_v2<T, N>::Pool_v2()
:sz{ N }, space{ new T [N] },
lst_unalloc{}, lst_alloc{}
{
for (size_t i = 0; i < N; ++i)
lst_unalloc.push_back(space + i);
}
template<typename T, int N>
T* Pool_v2<T, N>::get()
{
//O(1)分配时间
if (lst_unalloc.size() == 0)
return 0;
//将空闲链表的第一个元素分配出去
auto np = lst_unalloc.begin();
Node<T*>* pnode = np.get_pnode();
lst_unalloc.erase(np);
//将节点插入到已分配对象链表的头部
lst_alloc.insert(lst_alloc.begin(), pnode);
return pnode->val;
}
template<typename T, int N>
void Pool_v2<T, N>::free(T* obj)
{
//释放慢,需要先从已分配链表中找到该节点并删除,之后插入到空闲链表的正确位置
//遇到随机释放就特别慢
//*obj = T{}; //将归还的对象设置为默认值
for(auto pla = lst_alloc.begin(); pla != lst_alloc.end(); ++pla)
if(*pla == obj) //找到了
{
for (auto plua = lst_unalloc.begin(); plua != lst_unalloc.end(); ++plua)
if (*plua > obj) //空闲链表按内存位置从小到大排序
lst_unalloc.insert(plua, pla.get_pnode());
}
}
template <typename T, int N>
Pool_v2<T, N>::~Pool_v2()
{
delete[] space;
}
Stack.h
用 bitset 跟踪和标记每个对象的首地址索引
#include <iostream>
#include <bitset>
using std::cerr;
using std::bitset;
template<int N>class Stack { // stack of N bytes
public:
Stack(); // make an N byte stack
void* get(int n); // allocate n bytes from the stack;
// return 0 if no free space
void free(); // return the last value returned by get() to the stack
int available() const; // number of available bytes
private:
int sz; // total size of bytes
int free_sz; // size of available bytes
int top; // top of stack pointer which points to first byte of unallocated area
bitset<N> flag; // N位标记N字节,为1说明这个字节是已分配对象的第一个字节
char* space; // stack space
// 为了跟踪分配的
};
template <int N>
Stack<N>::Stack()
:sz{ N }, free_sz{ N }, top{0},
flag{ 0 }, space{ new char[N] }
{
}
template <int N>
void* Stack<N>::get(int n)
{
if(n < 0)
{
cerr << "non-positive size\n";
return nullptr;
}
else if (n > free_sz)
{
cerr << "no enough space\n";
return nullptr;
}
char* ret = &space[top];
flag.set(top);
top += n;
free_sz -= n;
return static_cast<void*>(ret);
}
template <int N>
void Stack<N>::free()
{
if (top == 0) //栈已经是空的
return;
//接下来遍历 flag,寻找栈顶对象的第一个字节位置
size_t i;
for(i = top-1; i >= 0; --i)
{
//space[i] = 0xCC; //清除数据,可选的操作
if (flag.test(i))
break;
}
size_t n{ top - i }; //栈顶对象的大小
top = i;
flag.set(top, false); // == flag.reset(top);
free_sz += n;
}
template <int N>
int Stack<N>::available() const
{
return free_sz;
}
25.2
#include "../../std_lib_facilities.h"
int main()
try
{
//初始化一个映射向量,将数字(索引)映射为英文字母串
const vector<string> n2c{
"o","l","to","three","for","five","six","seven",
"eight", "nine", "a", "b", "c", "d", "e", "f" };
const size_t base = n2c.size();
//设置为读入十六进制数字,并能够正确解释前缀0x
cin.unsetf(ios::dec | ios::oct);
cin >> hex;
int num{ -1 };
cin >> num;
while(num < 0)
{
cout << "number must be positive, try again\n";
cin >> num;
}
//接下来对数字进行转换为英文字母串
vector<string>temp; //临时存放每一位十六进制数对应的英文字母串,从低位到高位
if (num == 0)
temp.push_back(n2c[num]);
while(num > 0)
{
vector<string>::size_type i = num % base;
temp.push_back(n2c[i]);
num /= base;
}
//将逆序变成顺序
reverse(temp.begin(), temp.end());
//第一个字符串的第一个字母大写
temp[0][0] = toupper(temp[0][0]);
//输出
for (const string& s : temp)
cout << s;
cout << '\n';
return 0;
}
catch(runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch(...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.3
#include <bitset>
#include "../../std_lib_facilities.h"
int main()
try
{
const size_t hex_bits{ 2 }; //一个字节对应两位十六进制数
//32位有符号整数
{
int x;
bitset<8 * sizeof(x)> b;
//全0
b = 0;
x = 0;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(x) * hex_bits) << setfill('0') << x
<< "\tbin: " << b << '\n';
//全1
x = -1;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(x) * hex_bits) << setfill('0') << x
<< "\tbin: " << b << '\n';
//1和0交替(最高有效位为1)
x = 0xaaaaaaaa;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//0和1交替(最高有效位为0)
x = 0x55555555;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//两个1和两个0交替
x = 0xcccccccc;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//两个0和两个1交替
x = 0x33333333;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//全1字节和全0字节交替
x = 0xff00ff00;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//全0字节和全1字节交替
x = 0x00ff00ff;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
}
cout << "\n\n";
//无符号重做
{
unsigned int x{ 0 };
bitset<8 * sizeof(x)> b;
//全0
b = 0;
x = 0;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(x) * hex_bits) << setfill('0') << x
<< "\tbin: " << b << '\n';
//全1
x = -1;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(x) * hex_bits) << setfill('0') << x
<< "\tbin: " << b << '\n';
//1和0交替(最高有效位为1)
x = 0xaaaaaaaa;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//0和1交替(最高有效位为0)
x = 0x55555555;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//两个1和两个0交替
x = 0xcccccccc;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//两个0和两个1交替
x = 0x33333333;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//全1字节和全0字节交替
x = 0xff00ff00;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
//全0字节和全1字节交替
x = 0x00ff00ff;
b = x;
cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
<< setw(sizeof(short unsigned int) * 2) << setfill('0') << x
<< "\tbin: " << b << '\n';
}
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.4 Calculator
由于位运算只能用于整型,因此把计算器修改为整型运算计算器
/*
25_4-Calculator.cpp
本程序实现了一个简单的表达式计算器,支持变量操作,添加了帮助信息
添加了位运算,根据优先级设置语法。
~优先级最高,在Primary中,& ^ | 优先级以此降低,且他们三个都低于加法和减法符号
位运算只能整型,所以我就把所有的double替换为int了
从cin读入,输出到cout。
输入文法如下:
Calculation:
Statement
Print
Quit
Calculation Statement
Print:
';'
Quit:
'q'
"quit"
Statement:
Declaration
Expression_bit_or
Declaration:
"let" name '=' Expression
"const" name '=' Expression
//Expression_bit_or,意味着表达式中可能带有位运算符
Expression_bit_or
Expression_bit_xor
Expression_bit_or '|' Expression_bit_xor
Expression_bit_xor
Expression_bit_and
Expression_bit_xor '^' Expression_bit_and
Expression_bit_and
Expression
Expression_bit_and '&' Expression
Expression:
Term
Expression '+' Term
Expression '-' Term
Term:
Primary
Term * Primary
Term / Primary
Term % Primary
Primary:
Number
'(' Expression_bit_or ')'
-Primary //处理负数
~Primary //按位取反
Assignment
Number:
floating-point-literal
Assignment:
name '=' Expression
*/
#include "../../std_lib_facilities.h"
struct Token {
char kind;
int value;
string name;
Token(char ch) :kind(ch), value(0) { }
Token(char ch, int val) :kind(ch), value(val) { }
Token(char ch, string n) :kind(ch), name(n) { }
};
class Token_stream {
private:
bool full;
Token buffer;
public:
Token_stream() :full(false), buffer(0) { } // The constructor just sets full to indicate that the buffer is empty:
Token get();
void putback(Token t);
void ignore(char);
};
const string declkey = "let";
const char let = 'L';
const string quitkey = "quit";
const char quit = 'q';
const string helpkey = "help";
const char help = 'h';
const char print = ';';
const char number = '8';
const char name = 'a';
const char assign = '=';
const char con = 'C';
const string constkey = "const";
Token Token_stream::get()
{
if (full)
{
full = false;
return buffer;
}
char ch;
//cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.)
while (isspace((ch = cin.get())) && ch != '\n')
continue;
switch (ch) {
case '(': case ')':
case '+': case '-':
case '*': case '/': case '%':
case '~': case '&': case '^': case '|':
case '=':
case quit:
case print:
return Token{ ch }; // let each character represent itself
case '\n':
return Token{ print };
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch); // put digit back into the input stream
//cin.unget(); // same as putback(char), except no parameter
int val;
cin >> val; // read a floating-point number
return Token{ number, val };
}
default:
if (isalpha(ch)) {
string s;
s += ch;
//名字为字母开头的,带字母数字和下划线的字符串
while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_'))
s += ch;
cin.putback(ch);
if (s == declkey) return Token{ let }; // 声明变量关键字
if (s == constkey) return Token{ con }; // 声明常量关键字
if (s == helpkey || (s.size() == 1 && s[0] == help)) return Token{ help };
if (s == quitkey) return Token{ quit };
return Token{ name, s };
}
error("Bad token");
}
}
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
if (full)
error("putback() into a full buffer.");
buffer = t;
full = true;
}
void Token_stream::ignore(char c)
{
if (full && c == buffer.kind) {
full = false;
return;
}
full = false;
char ch;
while (cin >> ch)
if (ch == c) return;
}
//---------------------------------------------------------
// set Variable
class Variable {
public:
string name;
int value;
bool is_const;
Variable(string n, int v, bool b) :name(n), value(v), is_const(b) { }
};
class Symbol_table {
public:
Symbol_table() {}
int get(string var);
void set(string var, int d);
bool is_declared(string var);
int define(string var, int val, bool is_const);
private:
vector<Variable> var_table;
};
int Symbol_table::get(string s)
{
for (const Variable& v : var_table)
if (v.name == s)
return v.value;
error("get: undefined name ", s);
}
void Symbol_table::set(string s, int d)
{
for (Variable& v : var_table)
if (v.name == s)
{
if (v.is_const)
error("set: can not assign to a const ", s);
v.value = d;
return;
}
error("set: undefined name ", s);
}
bool Symbol_table::is_declared(string var)
{
//判断var是否已经在var_table中了
for (const Variable& v : var_table)
if (v.name == var)
return true;
return false;
}
int Symbol_table::define(string var, int val, bool is_const)
{
//将(var, val)加入var_table中
if (is_declared(var))
error(var, " declared twice");
var_table.push_back(Variable{ var, val, is_const });
return val;
}
Token_stream ts;
Symbol_table st;
//--------Expression---------------
int expression_bit_or();
int expression_bit_xor();
int expression_bit_and();
int expression();
int assignment(string var)
{
// 函数假设已经读入了赋值语句的左值和赋值符号
int right = expression();
st.set(var, right);
return right;
}
int primary()
{
Token t = ts.get();
switch (t.kind) {
case '(':
{
int d = expression_bit_or();
t = ts.get();
if (t.kind != ')')
error("'(' expected");
return d;
}
case '-':
return -primary();
case '~': //按位取反
return ~primary();
case number:
return t.value;
case name:
{
Token t2 = ts.get();
if (t2.kind != assign)
{
ts.putback(t2);
return st.get(t.name); // if next char is not a assignment operator, then return variable value
}
else
return assignment(t.name);
}
default:
error("primary expected");
}
}
int term()
{
int left = primary();
while (true) {
Token t = ts.get();
switch (t.kind) {
case '*':
left *= primary();
break;
case '/':
{
int d = primary();
if (d == 0) error("divide by zero");
left /= d;
break;
}
case '%':
{
int d = primary();
if (d == 0) error("divide by zero");
left = fmod(left, d);
break;
}
default:
ts.putback(t);
return left;
}
}
}
int expression()
{
int left = term();
while (true) {
Token t = ts.get();
switch (t.kind) {
case '+':
left += term();
break;
case '-':
left -= term();
break;
default:
ts.putback(t);
return left;
}
}
}
int expression_bit_and()
{
int left = expression();
while (true) {
Token t = ts.get();
if (t.kind == '&')
left &= expression();
else
{
ts.putback(t);
return left;
}
}
}
int expression_bit_xor()
{
int left = expression_bit_and();
while (true) {
Token t = ts.get();
if (t.kind == '^')
left ^= expression_bit_and();
else
{
ts.putback(t);
return left;
}
}
}
int expression_bit_or()
{
int left = expression_bit_xor();
while(true) {
Token t = ts.get();
if (t.kind == '|')
left |= expression_bit_xor();
else
{
ts.putback(t);
return left;
}
}
}
int declaration(char kind)
{
Token t = ts.get();
if (t.kind != name)
error("name expected in declaration");
string var_name = t.name;
Token t2 = ts.get();
if (t2.kind != '=')
error("= missing in declaration of ", var_name);
int d = expression_bit_or();
bool is_const = kind == con;
st.define(var_name, d, is_const);
return d;
}
int statement()
{
Token t = ts.get();
switch (t.kind) {
case let:
case con:
return declaration(t.kind);
default:
ts.putback(t);
return expression_bit_or();
}
}
void clean_up_mess()
{
ts.ignore(print);
}
const string prompt = "> ";
const string result = "= ";
void help_message()
{
cout << "Please enter expressions using floating-point numbers.\n";
cout << "You can use \"+ - * / %\" operators, ";
cout << "';' or type in Enter to output result, 'h' to help, and 'q' to quit.\n";
cout << "You can also define variables and constant by using let and const" << endl;
cout << "For example: let a = 1 define a variable a, const b = a * 3 define a constant b" << endl;
}
void calculate()
{
while (true)
try {
cout << prompt;
Token t = ts.get();
while (t.kind == print) t = ts.get(); // 丢弃之前的所有打印字符
if (t.kind == quit) return;
if (t.kind == help)
{
help_message();
continue;
}
ts.putback(t);
cout << result << statement() << endl;
}
catch (runtime_error& e) {
cerr << e.what() << endl;
clean_up_mess();
}
}
int main()
try {
cout << "Welcome to our simple calculator.\n";
cout << "Please enter expressions using floating-point numbers.\n";
cout << "You can use \"+ - * / %\" operators, ';' to output result, 'h' to help, and 'q' to quit.\n";
cout << "You can also define variables and constant by using let and const" << endl;
cout << "For example: let a = 1 define a variable a, const b = a * 3 define a constant b" << endl;
calculate();
return 0;
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
char c;
while (cin >> c && c != ';');
return 1;
}
catch (...) {
cerr << "exception\n";
char c;
while (cin >> c && c != ';');
return 2;
}
25.5 and 25.6 较难发现的无限循环
#include "../../std_lib_facilities.h"
int main()
try
{
//这是一个无限循环,为什么呢?
//需要反汇编解释,变量 i 的值mov到寄存器是 movsx
//而变量 max 的值mov到寄存器是 movzx
//由于 i 是有符号数,因此当超过127后,movsx 的效果是把 i 的值进行符号拓展后放到寄存器
//所以存放 i 的寄存器的高位是 1,而此时存放 max 的寄存器的高位是 0
//但是 i < max 这个判断是否跳出循环的比较,VS2019编译器用的指令是 jge
//那么只要 max 超过128,i jge 的结果必然表明 i < max,所以无限循环
unsigned char max = 128;
for (signed char i = 0; i < max; ++i)
cout << int(i) << '\n';
//下面的不会无限循环,因为 能满足 jge,所以循环会结束
unsigned int max2 = 1 << 31;;
for (signed int i = 0; i < max2; ++i)
cout << int(i) << '\n';
//我认为这个无限循环特性与编译器有关,可能换一种编译器就不会无限循环了
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.7
#include "../../std_lib_facilities.h"
int main()
try
{
for (int i = 0; i <= 400; ++i)
cout << dec << setw(5) << i << hex << setw(10) << i << '\n';
cout << '\n';
for(int i = -200; i <= 200; ++i)
cout << dec << setw(5) << i << hex << setw(10) << i << '\n';
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.8
#include "../../std_lib_facilities.h"
int main()
try
{
cout << "Enter character on your keyboard\n";
char ch;
while (cin.get(ch))
cout << ch << ": " << int(ch) << '\n';
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.9
#include "../../std_lib_facilities.h"
int main()
try
{
//确定 int 包含多少位
int cnt{ 0 };
int i = 0;
for (i = ~i; i != 0; i <<= 1)
++cnt;
cout << "int is " << cnt << " bits\n";
//确定 char 是有符号的还是无符号的
cnt = 0;
char j = 0;
for (j = ~j; j != 0; j <<= 1)
++cnt;
cout << "char is " << cnt << " bits\n";
char j1 = 1 << (cnt - 1);
char j2 = ~j1;
if (j1 > j2)
cout << "char is unsigned\n";
else
cout << "char is signed\n";
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.10 and 25.11 位域,无符号数位运算,bitset<>
#include "../../std_lib_facilities.h"
#include <bitset>
struct PPN
{
unsigned int PFN : 22; //页帧号
int : 3; //未用,因此未命名
unsigned int CCA : 3; //协同缓存算法
bool nonreachable : 1;
bool dirty : 1;
bool valid : 1;
bool global : 1;
};
void print_ppn(struct PPN& ppn)
{
cout << "PFN: " << ppn.PFN << '\n';
cout << "CCA: " << ppn.CCA << '\n';
cout << "nonreachable: " << boolalpha << ppn.nonreachable << '\n';
cout << "dirty: " << ppn.dirty << '\n';
cout << "valid: " << ppn.dirty << '\n';
cout << "global: " << ppn.global << '\n';
cout << noboolalpha;
}
void print_ppn(const unsigned int ppn)
{
cout << "PFN: " << ((ppn>>10) & 0x3FFF) << '\n';
cout << "CCA: " << ((ppn >> 4) & 0x7) << '\n';
cout << "nonreachable: " << boolalpha << ((ppn >> 3) & 0x1) << '\n';
cout << "dirty: " << ((ppn >> 2) & 0x1) << '\n';
cout << "valid: " << ((ppn >> 1) & 0x1) << '\n';
cout << "global: " << (ppn & 0x1) << '\n';
cout << noboolalpha;
}
void print_ppn(const bitset<32> ppn)
{
bitset<32> pfn_mask{ 0xfffffc00 };
cout << "PFN: " << ((ppn & pfn_mask) >> 10).to_ulong() << '\n';
bitset<32> cca_mask{ 0x70 };
cout << "CCA: " << ((ppn & cca_mask) >> 4).to_ulong() << '\n';
cout << "nonreachable: " << boolalpha << ppn[3] << '\n';
cout << "dirty: " << ppn[2] << '\n';
cout << "valid: " << ppn[1] << '\n';
cout << "global: " << ppn[0] << '\n';
cout << noboolalpha;
}
int main()
try
{
//用位域 bitfield 表示 PPN
PPN ppn1{ 256, 7,false,true,true,false };
print_ppn(ppn1);
cout << '\n';
ppn1.PFN = 0xff;
ppn1.CCA = 5;
ppn1.nonreachable = true;
ppn1.dirty = !ppn1.dirty;
ppn1.valid = !ppn1.valid;
ppn1.global = !ppn1.global;
print_ppn(ppn1);
cout << '\n';
//用32位无符号数表示 PPN
cout << "32 bits unsigned\n";
unsigned int ppn2{ 0x00040076 };
print_ppn(ppn2);
cout << '\n';
ppn2 = (0xff << 10) | (0x5 << 4) | (0x1 << 3) | (0x0 << 2) | (0x0 << 1) | 0x1;
print_ppn(ppn2);
cout << '\n';
//用 bitset<32>
cout << "bitset<32>\n";
bitset<32> ppn3 { string{"00000000000001000000000001110110"} };
print_ppn(ppn3);
cout << '\n';
//设置新的pfn
bitset<32> pfn_mask{ 0xfffffc00 };
ppn3 &= ~pfn_mask;
ppn3 |= 0xff << 10;
//设置新的cca
bitset<32> cca_mask{ 0x70 };
ppn3 &= ~cca_mask;
ppn3 |= 5 << 4;
//设置其余标识位
ppn3.set(3);
ppn3.reset(2);
ppn3.flip(1);
ppn3[0] = true;
print_ppn(ppn3);
cout << '\n';
return 0;
}
catch (runtime_error& e)
{
cerr << "Runtime error: " << e.what() << endl;
return 1;
}
catch (...)
{
cerr << "Exception occurred!\n";
return 2;
}
25.12
这个我就直接用了随书的源代码了
//
// This is example code from Chapter 25.5.6 "An Example: Simple encryption" of
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//
#include "../../std_lib_facilities.h"
//------------------------------------------------------------------------------
void encipher(
const unsigned long *const v,
unsigned long *const w,
const unsigned long * const k)
{
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0;
unsigned long delta = 0x9E3779B9;
unsigned long n = 32;
while(n-->0) {
y += (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
sum += delta;
z += (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
}
w[0]=y; w[1]=z;
}
//------------------------------------------------------------------------------
// Here is the corresponding deciphering function:
void decipher(
const unsigned long *const v,
unsigned long *const w,
const unsigned long * const k)
{
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0xC6EF3720;
unsigned long delta = 0x9E3779B9;
unsigned long n = 32;
// sum = delta<<5, in general sum = delta * n
while(n-->0) {
z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
sum -= delta;
y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
}
w[0]=y; w[1]=z;
}
//------------------------------------------------------------------------------
int main() // reciever
try
{
const int nchar = 2*sizeof(long); // 64 bits
const int kchar = 2*nchar; // 128 bits
string op;
string key;
string infile;
string outfile;
cout << "please enter inputfile name, output file name, and key:\n";
cin >> infile >> outfile >> key;
while (key.size()<kchar) key += '0'; // pad key
ifstream inf(infile.c_str());
ofstream outf(outfile.c_str());
if (!inf || !outf) error("bad file name");
const unsigned long* k =
reinterpret_cast<const unsigned long*>(key.data());
unsigned long inptr[2];
char outbuf[nchar+1];
outbuf[nchar]=0; // terminator
unsigned long* outptr = reinterpret_cast<unsigned long*>(outbuf);
inf.setf(ios_base::hex ,ios_base::basefield); // use hexadecimal input
while (inf>>inptr[0]>>inptr[1]) {
decipher(inptr,outptr,k);
outf<<outbuf;
}
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
return 1;
}
catch (...) {
cerr << "Oops: unknown exception!\n";
return 2;
}
25.14 Vector, Pool 作为分配器
感觉题意有些不清晰
#include <iostream>
#include "Pool.h"
using namespace std;
template<typename T, int N, typename Alloc = Pool_v1<T, N>> //Pool_v2也可以
class vector
{
Alloc alloc;
size_t sz;
T* elem[N]; //跟踪对象的指针数组
public:
vector();
T& operator[](int n);
void push_back(const T& elem);
int size() const { return sz; }
};
template <typename T, int N, typename Alloc>
vector<T, N, Alloc>::vector()
:alloc{}, sz{ 0 }
{}
template <typename T, int N, typename Alloc>
T& vector<T, N, Alloc>::operator[](int n)
{
//不提供范围检查
return *elem[n];
}
template <typename T, int N, typename Alloc>
void vector<T, N, Alloc>::push_back(const T& v)
{
if(sz == N)
{
cerr << "no enough space\n";
return;
}
elem[sz] = alloc.get();
*elem[sz] = v;
++sz;
}
int main()
{
vector<int, 10> pv1;
pv1.push_back(5);
cout << "pv1.size(): " << pv1.size() << '\n';
cout << "pv1[0]: " << pv1[0] << '\n';
vector<int, 1000> pv2;
for (int i = 0; i < 1000; ++i)
pv2.push_back(i);
for (size_t i = 0; i < pv2.size(); ++i)
cout << pv2[i] << '\n';
cout << "pv2.size(): " << pv2.size() << '\n';
return 0;
}
25.15 测试 new / delete, Pool, Stack 的分配与释放速度
产生随机序列的算法很有意思
#include <chrono>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<string>
#include<vector>
#include<algorithm>
#include<random>
#include<stdexcept>
#include "Pool.h"
#include "Stack.h"
using namespace std;
using namespace chrono;
inline int randint(int min, int max)
{
static default_random_engine ran(time(0));
return uniform_int_distribution<>{min, max}(ran);
}
inline int randint(int max) { return randint(0, max); }
inline void test_new_v1(int repn);
inline void test_new_v2(int repn);
inline void test_Pool_v1(int repn);
inline void test_Pool_v2(int repn);
inline void test_Stack(int repn);
int main()
{
const int repn{ 1000 }; //重复次数
//test_new_v1(repn);
//test_new_v2(repn);
//test_Pool_v1(repn);
//test_Pool_v2(repn);
test_Stack(repn);
return 0;
}
inline void test_new_v1(int repn)
{
//用 new 分配10000个对象所花费时间,对象大小为1字节到1000字节之间的随机值,
//然后用 delete 按分配的逆序进行释放,测试时间。
//参数 repn为重复次数
const int n_objs{ 10000 };
const int min_obj_sz{ 1 };
const int max_obj_sz{ 1000 };
vector<char*> v1(n_objs); //存储 n_objs 个对象指针
//开始计时
auto t1 = system_clock::now();
for (int i = 0; i < repn; ++i)
{
for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
{
size_t alloc_sz = randint(min_obj_sz, max_obj_sz);
v1[i] = new char[alloc_sz];
}
//按分配的逆序进行释放
for (vector<char*>::size_type i = v1.size() - 1; i < v1.size(); --i)
delete[] v1[i];
}
auto t2 = system_clock::now();
//计时结束
cout << "Allocating " << n_objs << " objects by new "
<< "and delete by reverse order " << repn <<" times took "
<< duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}
inline void test_new_v2(int repn)
{
//用 new 分配10000个对象所花费时间,对象大小为1字节到1000字节之间的随机值,
//然后用 delete 按随机顺序进行释放,测试时间
//参数 repn为重复次数
const int n_objs{ 10000 };
const int min_obj_sz{ 1 };
const int max_obj_sz{ 1000 };
vector<char*> v1(n_objs); //存储 n_objs 个对象指针
//获得随机释放的序列顺序
vector<vector<char*>::size_type> v_rand_i(v1.size());
for (vector<char*>::size_type i = 0; i < v_rand_i.size(); ++i)
v_rand_i[i] = i;
for (vector<char*>::size_type i = 1; i < v_rand_i.size(); ++i)
swap(v_rand_i[i], v_rand_i[randint(i)]);
//开始计时
auto t1 = system_clock::now();
for (int i = 0; i < repn; ++i)
{
for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
{
size_t alloc_sz = randint(min_obj_sz, max_obj_sz);
v1[i] = new char[alloc_sz];
}
//按随机顺序进行释放
for (const int i : v_rand_i)
delete[] v1[i];
}
auto t2 = system_clock::now();
//计时结束
cout << "Allocating " << n_objs << " objects by new "
<< "and delete by random order " << repn << " times took "
<< duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}
//500字节的对象
struct Obj500
{
char c[500];
};
void test_Pool_v1(int repn)
{
//从存储池 Pool_v1 中分配 10,000 个大小固定为 500 字节的对象
//然后 按随机顺序进行释放,测试时间
//参数 repn为重复次数
const int n_objs{ 10000 };
Pool_v1<Obj500, n_objs> pool_v1;//存储池
vector<Obj500*> v1(n_objs); //存储 n_objs 个对象指针
//获得随机释放的序列顺序
vector<vector<char*>::size_type> v_rand_i(v1.size());
for (vector<char*>::size_type i = 0; i < v_rand_i.size(); ++i)
v_rand_i[i] = i;
for (vector<char*>::size_type i = 1; i < v_rand_i.size(); ++i)
swap(v_rand_i[i], v_rand_i[randint(i)]);
//开始计时
auto t1 = system_clock::now();
for (int i = 0; i < repn; ++i)
{
for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
v1[i] = pool_v1.get();
//按随机顺序进行释放
for (const int i : v_rand_i)
pool_v1.free(v1[i]);
}
auto t2 = system_clock::now();
//计时结束
cout << "Allocating " << n_objs << " objects by Pool_v1 "
<< "and delete by random order " << repn << " times took "
<< duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}
void test_Pool_v2(int repn)
{
//从存储池 Pool_v2 中分配 10,000 个大小固定为 500 字节的对象
//然后 按随机顺序进行释放,测试时间
//参数 repn为重复次数
const int n_objs{ 10000 };
Pool_v2<Obj500, n_objs> pool_v2;//存储池
vector<Obj500*> v1(n_objs); //存储 n_objs 个对象指针
//获得随机释放的序列顺序
vector<vector<char*>::size_type> v_rand_i(v1.size());
for (vector<char*>::size_type i = 0; i < v_rand_i.size(); ++i)
v_rand_i[i] = i;
for (vector<char*>::size_type i = 1; i < v_rand_i.size(); ++i)
swap(v_rand_i[i], v_rand_i[randint(i)]);
//开始计时
auto t1 = system_clock::now();
for (int i = 0; i < repn; ++i)
{
for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
v1[i] = pool_v2.get();
//按随机顺序进行释放,释放速度极慢
for (const int i : v_rand_i)
pool_v2.free(v1[i]);
}
auto t2 = system_clock::now();
//计时结束
cout << "Allocating " << n_objs << " objects by Pool_v2 "
<< "and delete by random order " << repn << " times took "
<< duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}
void test_Stack(int repn)
{
//从 Stack 中分配 10000 个大小为 1 字节 到 1000 字节之间随机数的对象
//然后按逆序进行释放,测试时间
//参数 repn为重复次数
constexpr int n_objs{ 1000 };
constexpr int min_obj_sz{ 1 };
constexpr int max_obj_sz{ 1000 };
Stack<n_objs* max_obj_sz> st;
vector<char*> v1(n_objs); //存储 n_objs 个对象指针
//开始计时
auto t1 = system_clock::now();
for (int i = 0; i < repn; ++i)
{
for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
{
size_t alloc_sz = randint(min_obj_sz, max_obj_sz);
v1[i] = static_cast<char*>(st.get(alloc_sz));
}
//按分配的逆序进行释放,这里利用了栈的特性,无需指定专门的逆序索引
for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
st.free();
}
auto t2 = system_clock::now();
//计时结束
cout << "Allocating " << n_objs << " objects by Pool_v2 "
<< "and delete by random order " << repn << " times took "
<< duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}