这使我很好奇这些标量如何存储在“引擎盖”下,特别是在效率方面存在(是的,我知道脚本语言牺牲了灵活性的效率,但是当灵活性问题仍然需要时,它们仍然需要尽可能优化)不受影响).存储65535(这需要两个字节),然后是字符串“65535”,这需要6个字节,因为这样识别$val = 65535存储一个int将允许我使用1/3的内存容易得多,在大阵列中,这也意味着更少的缓存命中.
当然不仅限于节省内存.有时我可以提供更多的优化,如果我知道什么类型的标量期望.例如,如果我使用非常大的整数作为键的哈希值,如果我将密钥识别为int,则可以更快地查找一个值,允许简单的模式来创建我的哈希密钥,那么如果我必须运行更复杂的哈希一个字符串的逻辑,具有3倍的字节.
所以我想知道perl如何处理这些标尺.它是否将每个值作为字符串存储,在标量始终用作int的情况下,牺牲额外的内存和cpu常量将字符串转换为int的代价?还是有一些逻辑推理用于确定如何保存和操作的标量类型?
编辑:
TJD链接到perlguts,这回答了我的一半问题.标量实际上存储为字符串,int(signed,unsigned,double)或指针.我不是太惊讶,我主要是希望这种行为发生在引擎盖下,虽然看到确切的类型很有趣.我打开这个问题,因为perlgut实际上是低水平的.其他的告诉我有5种数据类型存在,它没有指定perl如何在它们之间进行交替,即如何在保存标量时如何决定使用哪种SV类型,以及如何知道何时/如何转换.
解决方法
虽然标量的类型表示标量可以包含什么,但标志用于指示标量所包含的内容.这被存储在FLAGS字段中. SVf_IOK表示标量包含有符号整数,而SVf_POK表示它包含一个字符串[2].
Devel::Peek的转储是查看标量内部的好工具. (Dump省略了常量前缀SVt_和SVf_)
$perl -e' use Devel::Peek qw( Dump ); my $x = 123; Dump($x); $x = "456"; Dump($x); $x + 0; Dump($x); ' SV = IV(0x25f0d20) at 0x25f0d30 <-- SvTYPE(sv) == SVt_IV,so it can contain an IV. REFCNT = 1 FLAGS = (IOK,pIOK) <-- IOK: Contains an IV. IV = 123 <-- The contained signed integer (IV). SV = PVIV(0x25f5ce0) at 0x25f0d30 <-- The SV has been upgraded to SVt_PVIV REFCNT = 1 so it can also contain a string now. FLAGS = (POK,IsCOW,pPOK) <-- POK: Contains a string (but no IV since !IOK). IV = 123 <-- Meaningless without IOK. PV = 0x25f9310 "456"\0 <-- The contained string. CUR = 3 <-- Number of bytes used by PV (not incl \0). LEN = 10 <-- Number of bytes allocated for PV. COW_REFCNT = 1 SV = PVIV(0x25f5ce0) at 0x25f0d30 REFCNT = 1 FLAGS = (IOK,POK,pIOK,pPOK) <-- Now contains both a string (POK) and an IV (IOK). IV = 456 <-- This will be used in numerical contexts. PV = 0x25f9310 "456"\0 <-- This will be used in string contexts. CUR = 3 LEN = 10 COW_REFCNT = 1
illguts文件内容变量的格式相当彻底,但perlguts可能是一个更好的起点.
如果您开始编写XS代码,请记住,检查标量包含通常是一个坏主意.相反,您应该请求应提供的内容(例如使用SvIV或SvPVutf8). Perl将自动将该值转换为请求的类型(如果适用,则警告). API调用记录在perlapi.
>所有标量(包括数组和散列,不包括只能容纳undef的标量类型)在其基础上有两个内存块.指向标量的指针指向其头部,其中包含TYPE字段和指向身体的指针.升级标量代替标量的正文.这样,升级的指针不会被无效.> undef变量是没有任何大写OK标志的变量.