罗韭菜的solidity学习(七)字节数组

可变长度的字节数组

1.string

  • 字符串可以通过" "或者' '来表示字符串的值,solidity中的string不像c语言一样以\0结束。
  • 它是可变长度的字节数组,为引用类型
  • string字符串不能通过length方法取其长度

2.byte

  • 动态字节数组,引用类型

3.string to byte
string字符串中没有提供length方法获取字符串长度,也没有提供方法修改某个索引的字节码,不过我们可以将string转换为bytes,再调用length方法获取字节长度,当然可以修改某个索引的字节码。

pragma solidity ^0.4.4;

contract C {
    
    bytes9 public g = 0x6c697975656368756e;
    
    string public name = "melodyluo";
    
    function gByteLength() constant returns (uint) {
        
        return g.length;
    }
    
// 转换string 到 bytes, 返回字节如g的内容,一共9字节,
// 也就是一个英文字母对应一个字节
function nameBytes() constant returns (bytes) {
        
        return bytes(name);
    }
    // 通过转换string to byte来调用length
    function nameLength() constant returns (uint) {
        
        return bytes(name).length;
    }
    
    function setNameFirstByteForL(bytes1 z) {
        
        // 0x4c => "L"
        bytes(name)[0] = z;
    }
}

4.汉字对应的字节数

  • 1个汉字对应3个字节
  • 1个英文字母、数字、特殊符号 对应1个字节
pragma solidity ^0.4.4;

contract C {
    
    
    string public name = "罗雪";
    

    function nameBytes() constant returns (bytes) {
        
        return bytes(name);//0x e7 bd 97 e9 9b aa 
        // 1 chinese word equals to 3 bytes
    }
    
    function nameLength() constant returns (uint) {
        
        return bytes(name).length;
    }
    
}
  • so不要混用字母、汉字之类的

5.创建bytes字节数组

  • new bytes(想要的字节长度)
  • 长度可变, length
  • 内容可变, name[index] = data
  • 可以通过让length=0来清空bytes数组,也可以直接delete;
pragma solidity ^0.4.4;

contract C {
    
    
    bytes public name = new bytes(1);
    
    
    function setNameLength(uint length) {
        
        name.length = length;
    }
    
    function nameLength() constant returns (uint) {
        
        return name.length;
    }
    
    function setIndextyte(byte data, uint indxe){
        name[indxe] = data;
    }
    
    function clearBBytes(uint len){
        delete name;
    }
    
}

6.push

  • 在字节数组的最后插入("0xbb")
pragma solidity ^0.4.4;

contract C {
    
    // 0x6c697975656368756e
    // 初始化一个两个字节空间的字节数组
    bytes public name = new bytes(2);
    
    // 设置字节数组的长度
    function setNameLength(uint len) {
        
        name.length = len;
    }
    
    // 返回字节数组的长度
    function nameLength() constant returns (uint) {
        
        return name.length;
    }
    
    // 往字节数组中添加字节
    function pushAByte(byte b) {
        
        name.push(b);
    }
    
}

-说明:当字节数组的长度只有2时,如果你通过push往里面添加了一个字节,那么它的长度将变为3,当字节数组里面有3个字节,但是你通过length方法将其长度修改为2时,字节数组中最后一个字节将被从字节数组中移除


固定长度的字节数组(byte1-byte32)

固定大小字节数组可以通过 bytes1, bytes2, bytes3, …, bytes32来进行声明。PS:byte的别名就是 byte1。

bytes1只能存储一个字节,也就是二进制8位的内容。
bytes2只能存储两个字节,也就是二进制16位的内容。
bytes3只能存储三个字节,也就是二进制24位的内容。
……
bytes32能存储三十二个字节,也就是二进制32 * 8 = 256 位的内容。

  • 根据经验,在我们不确定字节数据大小的情况下,我们可以使用string或者bytes,而如果我们清楚的知道或者能够将字节书控制在bytes1 ~ bytes32,那么我们就使用bytes1 ~ bytes32,这样的话能够降低存储成本。

运算

  • 比较运算符:<=, <, ==, !=, >=, >
  • 位操作符:&, |, ^(异或), ~ (取反), << (左移), >> (右移)
  • 注意左移与右移,如下
pragma solidity ^0.4.4;

 contract test{
 bytes1 b10 = 0x6c;
 bytes1 b11 = 0x69;
 
 function leftshift1() constant returns(bytes1) {
     return b10 << 1;
     // 0110 1100 -> 0x6c
     // 1101 1000 -> 0xd8
 }
 
  function fightshift1() constant returns(bytes1) {
     return b10 >> 1;
     // 0110 1100 -> 0x6c
     // 0011 0110 -> 0x36
 }
 
 }
 
  • 索引访问:如果x是一个bytes I,那么可以通过x[k](0 < k < I)获取对应索引的字节,PS:x[k]是只读,不可写。
pragma solidity ^0.4.4;

contract c{
    bytes9 b9 = 0x6c697975656368756e;
    function readIndex5Byte() constant returns(byte){
        return b9[5];
    }
}

成员函数

length

  • 返回字节的个数
  • 只可读不可写
pragma solidity ^0.4.4;

contract C {
    
    bytes9 public g = 0x6c697975656368756e;
    
    function gByteLength() constant returns (uint) {
        
        return g.length;
    }
    
}
image.png

固定大小深度理解

  • 存储的字节数不可修改(不能通过length修改)
  • 内部字节不可修改
pragma solidity ^0.4.4;

contract C {
    
    
    bytes9  name = 0x6c697975656368756e;
    
    function setNameFirstByte(byte b) {
        
        name[0] = b;
    }
    
}
image.png

总结

bytesI(1 <= I <= 32)可以声明固定字节大小的字节数组变量,一旦声明,内部的字节和字节数组长度不可修改,当然可以通过索引读取(只读)对应索引的字节,或者通过length读取字节数组的字节数。


不可变字节数组
我们之前的文章中提到过如果我们清楚我们存储的字节大小,那么我们可以通过bytes1,bytes2,bytes3,bytes4,……,bytes32来声明字节数组变量,不过通过bytesI来声明的字节数组为不可变字节数组,字节不可修改,字节数组长度不可修改。

可变字节数组
我们可以通过bytes name = new bytes(length) - length为字节数组长度,来声明可变大小和可修改字节内容的可变字节数组。


固定与可变字节数组之间的转换

1.固定字节数组之间的转换

  • 赋值是在最后,如
pragma solidity ^0.4.4;

contract C {
    bytes10 public b1 = 0x6c;
    
    function b_length() constant returns(uint){
        return b1.length;
    }
}
image.png
  • byte9 -> byte2 的转换, 低位截断,后面截掉
  • byte9 -> byte12 的转换,低位补齐,后面补零


    image.png

2.固定转可变

  • 不能直接强转成动态数组
  • 正确姿势如下
pragma solidity ^0.4.4;

contract C {
    
   bytes9 name9 = 0x6c697975656368756e;
   
   function transfer(bytes9) constant returns(bytes) {
       bytes memory names = new bytes(name9.length);
       for (uint i =0;i<name9.length;i++){
           names[i] = name9[i];
       }
       return names;
   }
    
}

3.固定不能直接转string
需要先固定转动态,动态转string
但是这种方法会有问题,如果将一个byte32(实际内容为9个字节)转string,string长度也是32,会有很多00000。这样不好,标准方法见5

pragma solidity ^0.4.4;

contract C {
    
   bytes9 name9 = 0x6c697975656368756e;
 
   function bytes9transfertostring(byte9 name9) constant returns(string){
       bytes memory names = new bytes(name9.length);
       
       for (uint i =0; i<name9.length; i++){
           names[i]=name9[i];
       }
       return string(names);
   }
}

4.动态字节转string

  • 如果有现成的动态字节数组如names,直接强转
pragma solidity ^0.4.4;

contract C {
    
   bytes9 name9 = 0x6c697975656368756e;
   
   bytes names = new bytes(2);
   
   function C(){
       names[0]=0x6c;
       names[1]=0x69;
   }
   
   function transfer() constant returns(string){
       return string(names);
   }
}

5.标准的固定字节转string方法
注意当要改变状态变量时不能用constant

pragma solidity ^0.4.4;

contract C {
    
    function bytes32ToString(bytes32 x) constant returns (string) {
        bytes memory bytesString = new bytes(32);
        uint charCount = 0;
        for (uint j = 0; j < 32; j++) {
            byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
            if (char != 0) {
                bytesString[charCount] = char;
                charCount++;
            }
        }
        bytes memory bytesStringTrimmed = new bytes(charCount);
        for (j = 0; j < charCount; j++) {
            bytesStringTrimmed[j] = bytesString[j];
        }
        return string(bytesStringTrimmed);
    }

    function bytes32ArrayToString(bytes32[] data) constant returns (string) {
        bytes memory bytesString = new bytes(data.length * 32);
        uint urlLength;
        for (uint i = 0; i< data.length; i++) {
            for (uint j = 0; j < 32; j++) {
                byte char = byte(bytes32(uint(data[i]) * 2 ** (8 * j)));
                if (char != 0) {
                    bytesString[urlLength] = char;
                    urlLength += 1;
                }
            }
        }
        bytes memory bytesStringTrimmed = new bytes(urlLength);
        for (i = 0; i < urlLength; i++) {
            bytesStringTrimmed[i] = bytesString[i];
        }
        return string(bytesStringTrimmed);
    }    
}
  • bytes32(uint(0x6c) * 2 ** (8 * 31));左移31位
    bytes32(uint(0x6c) * 2 ** (8 * 1)); 左移1位
  • 通过byte(bytes32(uint(x) * 2 ** (8 * j)))获取到的始终是第0个字节。

string本身是一个特殊的动态字节数组,所以它只能和bytes之间进行转换,不能和固定大小字节数组进行直接转换,如果是固定字节大小数组,需要将其转换为动态字节大小数组才能进行转换。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容