【C++】Digest of 《effective C++》--2

《effective c++》阅读笔记02

  • 条款01-视c++为一个语言联邦

如今的c++是一个多重范型编程语言(multiparadigm programming language),同时支持过程形式(procedual)、面相对象形式(object-oriented)、函数形式(functional)、泛型形式(generic)、元编程形式(metaprogramming)。

四个关键词

  • C
    c++是以c为基础的语言。blocks,statement,preprocessor,bulit-in types,arrays,pointers都来自c。
  • objective-oriented C++
    体现c with classes。构造函数、析构函数、封装、继承、多态,virtual函数(动态绑定)……
  • tmplate C++
    c++的泛型编程部分
  • STL
    STL是一个template程序库。

由于c++继承自c,所以,当处理内置类型的数据时,用pass-by-value比价高效,而处理自定义类型的时候,往往用pass-by-reference-to比较好。

又由于STL的迭代器和函数对象都是在c指针的基础上塑造出来的,所以用pass-by-value又比较好。

  • c++高效编程守则视状况变化,取决于你使用c++的哪一部分。

  • 条款02-尽量以const,enum,inline替换#define

#define所定义的记号是预处理器来处理的,所以在编译器编译之前,它就被预处理器移走了,因此,该记号没有进入记号表(symbol table)当我们定义如下:

#define ZERO 0

如果我们的程序出现编译错误时,这个错误信息会提到0而不是ZERO,因为这个记号是不在记号表里面的。而如果这个记号定义在一个非我们所写的头文件里,我们就会对这个莫名其妙的0没有概念,这将给团队合作的编程带来很大麻烦。

解决方法就是用常量代替上面的宏。即用const来定义一个常量表达式。
如:

const int zero = 0;

此时我们定义了一个语言常量,一定会进入记号表,所以会被编译器看到,这样出现错误信息的时候我们就比较容易理解。

当我们定义一个常量指针的时候要注意,要将指针而不只是指针所指之物声明为const,这时就要求我们写两次const

//example
const char* const name = "name";

tips:在c++里,使用string比char*要合宜,所以可以写成如下:
const std::string name = "name";

其次,如果我们要定义一个class专属常量,是没办法使用宏做到。这时我们需要让它成为一个class的成员,而为了使之只有一个实体,必须把它定义为static成员。

class GamePlayer {
private:
static const int NumTurns = 5; //注意这只是一个声明式而非定义式
int scores[NumTurns];
};

通常情况下,c++要求我们对我们使用的任何一样东西提供定义式,但如果它是一个class专属常量又是static且为整数类型,只要不取它们的地址,我们可以只是声明而不必要提供定义式。
如果需要取该常量的地址,则需要另外提供定义式。

const int GamePlayer::NumTurns; //因为声明时已经给予初值,所以定义时不可以再设初值。

若旧式的编译器不支持在声明时给予初值,则将初值的赋予放在定义式中进行。

这时出现新问题,如果声明式里不能给予初值,则上面的scores数组就编译不通过,因为编译器坚持必须在编译期间知道数组的大小。

解决方法是用所谓的“the enum hack”补偿做法
基于原理:一个属于枚举类型(enumerated type)的数值可权充int被使用

class GamePlayer {
private:
    enum{NumTurns = 5};
    int scores[NumTurns]; //ok,成功编译
};

enum hack的行为某方面说比较像#define而不像const,如取一个enum的地址是不合法的。如果不想让别人获得一个pointers或reference指向我们的某个整数常量,就可以用enum实现。

像函数的宏有着很多缺点,尽量避免使用,可以用template inline函数来代替。
如我们可以将以下宏

#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b)) //使用时会发现奇奇怪怪的错误

替换成

template<typename T>
inline void callWithMax(cosnt T& a, const T& b) {
    f(a > b ? a : b); //不用担心出现奇奇怪怪的错误
}

而且使用inline函数可以实现封装,而宏是实现不了的。

  • 对于单纯常量,最好以const对象或enums替换#define。
  • 对于形似函数的宏(macros),最好改用inline函数替换#defines。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SHA-1是一种加密哈希算法,它将任意长度的消息压缩为一个160位的消息摘要。下面是使用C++实现SHA-1算法的示例代码: ```c++ #include <iostream> #include <cstring> #include <cstdint> // 循环左移函数 #define ROTLEFT(a,b) ((a << b) | (a >> (32-b))) // 定义常量K const uint32_t K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; // SHA-1算法函数 void sha1(uint8_t* message, uint32_t message_length, uint32_t* digest) { // 初始化缓冲区 uint32_t H[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; // 计算填充位数 uint32_t padding_length = 64 - ((message_length + 8) % 64); // 填充消息 uint8_t* padded_message = new uint8_t[message_length + padding_length + 8]; std::memcpy(padded_message, message, message_length); padded_message[message_length] = 0x80; std::memset(padded_message + message_length + 1, 0, padding_length - 1); // 将消息长度添加到消息末尾 uint64_t message_bit_length = message_length * 8; std::memcpy(padded_message + message_length + padding_length, &message_bit_length, sizeof(message_bit_length)); // 处理每个512位的分组 for (uint32_t i = 0; i < message_length + padding_length + 8; i += 64) { // 将分组划分为16个32位的字 uint32_t* w = new uint32_t[80]; for (uint32_t j = 0; j < 16; j++) { w[j] = (padded_message[i + j * 4] << 24) | (padded_message[i + j * 4 + 1] << 16) | (padded_message[i + j * 4 + 2] << 8) | (padded_message[i + j * 4 + 3]); } // 扩展16个字为80个字 for (uint32_t j = 16; j < 80; j++) { w[j] = ROTLEFT(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); } // 初始化哈希值 uint32_t a = H[0]; uint32_t b = H[1]; uint32_t c = H[2]; uint32_t d = H[3]; uint32_t e = H[4]; // 主循环 for (uint32_t j = 0; j < 80; j++) { uint32_t f, k; if (j < 20) { f = (b & c) | ((~b) & d); k = K[0]; } else if (j < 40) { f = b ^ c ^ d; k = K[1]; } else if (j < 60) { f = (b & c) | (b & d) | (c & d); k = K[2]; } else { f = b ^ c ^ d; k = K[3]; } uint32_t temp = ROTLEFT(a, 5) + f + e + k + w[j]; e = d; d = c; c = ROTLEFT(b, 30); b = a; a = temp; } // 更新哈希值 H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; // 释放内存 delete[] w; } // 保存哈希值 std::memcpy(digest, H, sizeof(H)); // 释放内存 delete[] padded_message; } int main() { uint8_t message[] = "hello world"; uint32_t digest[5]; sha1(message, std::strlen((const char*)message), digest); std::cout << std::hex << digest[0] << digest[1] << digest[2] << digest[3] << digest[4] << std::endl; return 0; } ``` 注意,这只是一个简单的示例代码,实际应用中需要考虑更多安全性和性能方面的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值