个人笔记(3)
今天帮一个同事把CPP代码改成对应的python代码,cpp代码很简单,如下:
1 static inline
2 std::string calc_tid(uint32_t threshold, uint64_t filesize)
3 {
4 static const char trailing_bytes[] = {47, 13, 94, 118, 39, 71, 156, 59};
5 char values[16], hashed_md5[33];
6
7 const uint32_t vid = ~threshold;
8 const uint32_t lower_filesize = static_cast<uint32_t>(filesize);
9
10 std::memcpy(values, &vid, sizeof(vid));
11 std::memcpy(values + sizeof(vid), &lower_filesize, sizeof(lower_filesize));
12 std::memcpy(values + sizeof(vid) + sizeof(lower_filesize), trailing_bytes, sizeof(trailing_bytes));
13
14 //对values进行md5,并格式化成16进制字符串,得到tid_code。
15 md5_string(values, 16, hashed_md5);
16 return std::string(hashed_md5, 32);
17 }
18
19 static inline
20 std::string calc_fid(const std::string &cid, uint64_t file_size, const std::string &gcid)
21 {
22 if(cid.empty() || gcid.empty())
23 {
24 return std::string();
25 }
26
27 assert(cid.size() == 40);
28 assert(gcid.size() == 40);
29
30 std::string cid_binary = xdrive::unhex_string(cid);
31 std::string gcid_binary = xdrive::unhex_string(gcid);
32
33 char input[48];
34 std::memcpy( input , cid_binary.c_str() , cid_binary.size() );
35 std::memcpy( input + cid_binary.size() , &file_size , sizeof(file_size) );
36 std::memcpy( input + cid_binary.size() + sizeof(file_size) , gcid_binary.c_str() , gcid_binary.size() );
37
38 return Base64::encode(std::string(input, 48));
39 }
本来以为挺简单,做的时候才发现好多细节要注意,总结了一下,大概有以下几点:
1、C++中的整数转Python中的数
总所周知,python中的整数只有int和long两种形式,而c++中有很多种,而且还包括有符号和无符号。怎么在python中区分这些类型呢?
例如:
①CPP中uint32_t转uint32_t:
1 const uint32_t vid = ~threshold;
threshold是uint32_t类型,取反后赋值给vid,在python中改为:
1 vid = (~threshold) & 0xFFFFFFFF
算是强制转化为32位的。
②CPP中uint64_t转CPP中uint32_t:
1 const uint32_t lower_filesize = static_cast<uint32_t>(filesize);
file_size是uint64_t类型,截断为uint32_t,在python中改为:
1 lower_filesize = filesize & 0xFFFFFFFF
算是强制截断,取最后32位
2、对整数的memcpy
C++中可以直接操作内存,python中不需要直接操作内存(当然你也可以调用python的c接口来操作内存)
例如,CPP代码:
1 std::memcpy(values, &vid, sizeof(vid));
2 std::memcpy(values + sizeof(vid), &lower_filesize, sizeof(lower_filesize));
3 std::memcpy(values + sizeof(vid) + sizeof(lower_filesize), trailing_bytes, sizeof(trailing_bytes));
在python中需要把整形对应的内存数据转为字符串类拷贝,python代码如下:
1 vid_buff = struct.pack("I", vid)
2 file_size_buff = struct.pack("I", lower_filesize)
3 values = vid_buff + file_size_buff
4 n = len(trailing_bytes)
5 for i in range(0, n):
6 values = values + struct.pack("i", trailing_bytes[i])[0]
注意:
①这里用到了python的struct模块,先把整数转为str类型,然后直接追加就完成了memcpy的功能。转str类型时注意pack的格式,其中“I”表示的是unsigned int类型,字节数为4,“i”表示的是int类型,字节数为4,如果是无符号64位整数,可以用“Q”,其他情况可以自己查询。
②在整数(小于256)转为单字节字符时,这里先把对应的整数格式化为内存字符串,然后取第一个字节,具体取第一个字节还是最后一个字节,需要根据你自己的机器是大端还是小端来确定,切记!
3、字符对应的acsii码整数
使用python内置函数ord('A'), ord('0')即可
4、python的位操作与C语言是一样的
按位与(&),按位或(|),按位取反(~)
以上两个cpp函数改为python之后的代码如下:
1 #!/bin/env python 2 #coding=utf-8 3 4 import md5 5 import base64 6 import struct 7 8 def calc_tid(threshold, filesize): 9 trailing_bytes = [47, 13, 94, 118, 39, 71, 156, 59] 10 vid = (~threshold) & 0xFFFFFFFF 11 lower_filesize = filesize & 0xFFFFFFFF 12 13 vid_buff = struct.pack("I", vid) 14 file_size_buff = struct.pack("I", lower_filesize) 15 values = vid_buff + file_size_buff 16 n = len(trailing_bytes) 17 for i in range(0, n): 18 values = values + struct.pack("i", trailing_bytes[i])[0] 19 20 return md5.new(str(values)).hexdigest().upper() 21 22 23 def calc_fid(cid, file_size, gcid): 24 # if not cid or not gcid: 25 # return "" 26 27 # reg_p = r"[0-9a-fA-F]{40}$" 28 # pattern = re.compile(reg_p) 29 # if not pattern.match(cid) or not pattern.match(gcid): 30 # sys.exit(-1) 31 32 cid_binary = unhex_string(cid) 33 gcid_binary = unhex_string(gcid) 34 35 file_size_buff = struct.pack("Q", file_size) 36 37 input = cid_binary + file_size_buff + gcid_binary 38 39 return base64.encodestring(input)
参考资料:
1、http://www.cnblogs.com/gala/archive/2011/09/22/2184801.html
2、http://blog.csdn.net/JGood/article/details/4290158
3、http://www.cnblogs.com/tonychopper/archive/2010/07/23/1783501.html
4、http://blog.163.com/sukerl@126/blog/static/1120276492009111494052196/
5、http://bbs.chinaunix.net/thread-921983-1-1.html