关于 php 中 pack 、unpack、 ord 的理解和用法

本文详细介绍了PHP中的pack函数使用方法、ASCII码转换原理、常见格式说明,并通过实例展示了如何利用pack函数进行数据压缩打包,以及节省空间、加密等应用场景。同时,探讨了pack与unpack函数的结合使用,提供了代码示例帮助开发者掌握打包与解包技术。

pack函数说明:本函数用来将资料压缩打包到位的字符串之中。

首先  pack的 格式 为  pack('最原始数据使用的格式,'原始数据'');

pack('a1','h')或者pack('a*','h');

每个字母(比如上面的a)后面都可以跟着一个数字,表示count(计数)来解释成某种形式的重复计数或者长度(换算后字符长度发生了改变),具体情况取决于格式。除了a,A,b,B,h,H,P,和 Z 之外,所有格式的count 都是重复次数(也就是说 上面的这几个字符后面的“计数”指的是获取字符串的长度),ack('a*','h')字母(比如上面的a)后面都可以跟着一个数字,表示count(计数),解释成某种形式的重复计数或者长度,具体情况取决于格式。除了a,A,b,B,h,H,P,和 Z 之外,所有格式的count 都是重复次数(也就是说 上面的这几个字符后面的“计数”指的是获取字符串的长度),因此 pack 从 LIST 里吃进那么多数值(除了第一个参数,剩下的参数可以理解成都在一个列表中)。如果 count 是一个 *表示剩下的所有东西。【pack('a*',100,20) :只取第一个参数的所有字符  ,pack('C*',100,101,102):把这三个参数都换算pack('Cf'',224,3.14,100)  :C:换算244,f:换算剩下所有的参数】

理解:pack 返回的数据 都用通过 ASCII码换算过后的,如果单纯理解ASCII换算的话 ,可以用一个php函数  ord():返回字符串第一个字符的 ASCII 值。

比如 ord(‘h’)和ord(‘hello’)都是返回一个十进制数:114【占用三个字节】,而pack('a*','h')也返回114, 但是在ord的基础上对字节进行了 增加或者减少(也就是对位的增加减少)当前这个列子上没有增加也没减少   比如pack('C',100)  返回 一个字节为:d。

上面的"a" 指的是转成什么字符,“*”指的是剩下的所有东西,如果改成‘a1’的话 ,就是获取原始数据的第一个字符转成a格式的字符。

下面是pack所有的格式(网上全部都是列出来的,虽然一看见这么多 觉着恶心):

a 一个填充空的字节串
A 一个填充空格的字节串
b 一个位串,在每个字节里位的顺序都是升序
B 一个位串,在每个字节里位的顺序都是降序
c 一个有符号 char(8位整数)值
C 一个无符号 char(8位整数)值;关于 Unicode 参阅 U
d 本机格式的双精度浮点数
f 本机格式的单精度浮点数
h 一个十六进制串,低四位在前
H 一个十六进制串,高四位在前
i 一个有符号整数值,本机格式
I 一个无符号整数值,本机格式
l 一个有符号长整形,总是 32 位
L 一个无符号长整形,总是 32 位
n 一个 16位短整形,“网络”字节序(大头在前)
N 一个 32 位短整形,“网络”字节序(大头在前)
p 一个指向空结尾的字串的指针
P 一个指向定长字串的指针
q 一个有符号四倍(64位整数)值
Q 一个无符号四倍(64位整数)值
s 一个有符号短整数值,总是 16 位
S 一个无符号短整数值,总是 16 位
u 一个无编码的字串
U 一个 Unicode 字符数字
v 一个“VAX”字节序(小头在前)的 16 位短整数
V 一个“VAX”字节序(小头在前)的 32 位短整数
w 一个 BER 压缩的整数
x 一个空字节(向前忽略一个字节)
X 备份一个字节
Z 一个空结束的(和空填充的)字节串
@ 用空字节填充绝对位置


通过下面的代码 可以看出他们的不同:

//A字符
$str=(pack("A*", "中国"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


//H字符
$str=(pack("H*", "fffe"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


//C字符
$str=(pack("C*", "55","56","57"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str);
//i字符 短整形 32位 4个字节 64位8个字节
$str=(pack("i", "100"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


//s字符 短整形 2个字节
$str=(pack("s", "100"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


//l字符 长整形 4个字节
$str=(pack("l", "100"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


//f字符 单精度浮点 4个字节
$str=(pack("f", "100"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


//d字符 双精度浮点 8个字节
$str=(pack("d", "100"));
echo $str,"=",strlen($str),"字节\n";
getAscill($str); 


function getAscill($str)
{
$arr=str_split($str);
foreach ($arr as $v)
{
echo $v,"=",ord($v),"\n";
}
echo "=============\r\n\r\n";
}

/*pack作用:节省空间、加密格式 */

$code=array(
"username"=>array("A20","张三adfb12"),
"pass"=>array("A10","asdf*#1"),
"age"=>array("C","23"), //转成一个字节  节省了空间
"birthday"=>array("I","19900101"), //转成4个字节,想象一下 如果第二个参数长度一直增大比如‘199001010001256325’ ,到那时就更可以看出节省的空间了(因为不论多大 都是占用4个字节)
"email"=>array("A50","zhangsan@163.com")); //进行了加密
$stream=join("\0",packByArr($code));
echo $stream,strlen($stream);

file_put_contents("c:/1.txt",$stream);    //将流保存起来便于下面读取

function packByArr($arr)  {
         $atArr=array();
         foreach ($arr as $k=>$v) {
                  $atArr[]=pack($v[0],$v[1]);
         }
         return $atArr;
}
function getAscill($str) {
         $arr=str_split($str);
         foreach ($arr as $v) {
                  echo $v,"=",ord($v),"\n";
         }
}


Unpack解包
解包需要按照,打包方式读取,该读取多长,该用什么类型读取,必须与打包规定一样。
$code=array(
"username"=>array("A20"),
"pass"=>array("A10"),
"age"=>array("C"),
"birthday"=>array("I"),
"email"=>array("A50"));
$stream=file_get_contents("c:/1.txt");
var_dump(packByArr($stream,$code));
function packByArr($str,$code) {
         $Arr=explode("\0",$str);
         $atArr=array();
         $i=0;
         foreach ($code as $k=>$v) {
                  $atArr[$k]=unpack($v[0],$Arr[$i]);
                  $i++;
         }
         return $atArr;
}





<think>好的,用户想了解UVM中packunpack函数的使用方法,并且需要示例。首先,我需要回忆一下UVM中的packunpack的基本概念。这两个函数通常用于将对象序列化为比特流或者从比特流中还原对象,这在验证环境中传输数据时非常有用。 接下来,我需要确认用户的问题点。他们可能想知道如何在自己的测试平台中正确使用这两个函数,或者遇到了一些相关的错误。我需要确保回答涵盖基本用法、示例代码以及可能的常见问题。 首先,我应该解释packunpack的作用。pack函数将对象的属性转换成比特流,而unpack则相反。需要注意,这些函数是自动生成的,前提是使用`uvm_field_*宏注册字段。如果用户没有正确注册字段,可能会导致序列化失败。 然后,提供一个示例。需要定义一个继承自uvm_sequence_item的类,包含一些数据成员,比如addr、data、id等,并使用`uvm_field_int宏注册每个字段。接着,在测试用例中创建对象实例,调用packunpack方法,并输出结果以验证是否正确。 可能用户会遇到的常见问题包括字段未正确注册、字节顺序问题、或者打包解包后的数据不一致。因此,在注意事项部分需要提到这些点,提醒用户检查宏的使用字节顺序处理。 此外,用户可能需要了解如何自定义packunpack的行为,这时候需要重写do_packdo_unpack方法。这部分可以作为高级用法提及,但示例中保持基础用法会更清晰。 最后,生成相关问题,帮助用户进一步学习,比如如何调试打包错误,或者性能优化方法。这些问题应该与pack/unpack的使用紧密相关,并且引导用户深入理解UVM的数据处理机制。 现在需要确保回答符合用户的要求:结构清晰,步骤详细,示例正确,并且引用正确。同时,按照系统级指令,数学公式用$...$,独立公式用$$...$$,不过在这个问题中可能用不上太多数学公式,但需要保持LaTeX语法正确。另外,使用中文回答,生成相关问题,并在引用处添加标识。检查是否有站内引用需要添加,但根据用户提供的参考,似乎没有其他引用,因此可能不需要添加额外的引用标识。 总结回答的结构:首先介绍pack/unpack的作用,然后给出示例代码,分步骤解释,接着列出注意事项,最后生成相关问题。确保代码格式正确,使用SystemVerilog语法,并且解释清晰。</think># UVM中packunpack函数使用方法 ## 一、核心作用 pack函数将UVM对象转换为比特流(bitstream),实现数据序列化;unpack函数则将比特流还原为对象,完成反序列化。这两个函数常用于: - 跨进程通信(如通过TLM接口传输对象) - 数据持久化(如存储到文件) - 数据校验(比较序列化前后的数据一致性) ## 二、基础示例 ```systemverilog class my_transaction extends uvm_sequence_item; rand bit [31:0] addr; rand bit [63:0] data; rand int id; bit mode; `uvm_object_utils_begin(my_transaction) `uvm_field_int(addr, UVM_ALL_ON) `uvm_field_int(data, UVM_ALL_ON) `uvm_field_int(id, UVM_ALL_ON) `uvm_field_int(mode, UVM_ALL_ON) `uvm_object_utils_end function new(string name = "my_transaction"); super.new(name); endfunction endclass // 使用示例 my_transaction src = my_transaction::type_id::create("src"); my_transaction dst = my_transaction::type_id::create("dst"); byte unsigned stream[]; // 序列化操作 src.randomize(); src.pack(stream); // 将对象打包为字节数组 // 反序列化操作 dst.unpack(stream); // 从字节数组还原对象 ``` ## 三、关键步骤说明 1. **字段注册**:必须使用`uvm_field_*宏注册需要序列化的字段 ```systemverilog `uvm_field_int(addr, UVM_ALL_ON) // 注册32位整型 `uvm_field_real(data, UVM_ALL_ON) // 注册real类型 ``` 2. **字节流处理**:pack输出为动态字节数组,unpack输入需匹配格式 ```systemverilog byte unsigned stream[]; // 存储比特流的动态数组 src.pack(stream); // 打包后stream会自动调整大小 ``` 3. **验证结果**:可通过字段比较确认序列化正确性 ```systemverilog if(dst.compare(src)) `uvm_info("CHECK", "Unpack success", UVM_LOW) ``` ## 四、高级用法 ### 1. 自定义打包规则 通过重写`do_pack`/`do_unpack`方法实现特殊处理: ```systemverilog function void do_pack(uvm_packer packer); super.do_pack(packer); packer.pack_field_int(addr >> 2, 30); // 打包地址的高30位 endfunction ``` ### 2. 压缩优化 使用`UVM_NOPACK`标志跳过非必要字段: ```systemverilog `uvm_field_int(debug_info, UVM_ALL_ON|UVM_NOPACK) // 调试信息不参与打包 ``` ## 五、常见问题排查 | 现象 | 解决方案 | |------|----------| | 字段丢失 | 检查是否所有字段都正确注册 | | 字节数不符 | 验证字段位宽总是否为8的倍数 | | 数据错位 | 确认打包/解包使用相同字节序 | | 性能低下 | 减少动态数组字段的使用 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值