Um bit armazena um valor de 0 ou 1. Para armazenar mais do que 0 ou 1, esses bits são suspensos juntos em um grupo de 8 e, portanto, formam um byte. 1 byte representa 2⁸=256 posições. Esses bytes também podem ser combinados para criar uma memória maior. O byte também define a medida da memória de um computador, por exemplo, um computador tem uma memória de 2 KB (kilobytes), o que significa 2048 kilobytes. O bloco de memória é dividido em pequenas seções e é dedicado ao armazenamento. Eles podem ser 0 ou 1 e são chamados de bit. Enquanto escrevemos um código para um aplicativo, normalmente não lidamos com bits simplesmente porque a quantidade de memória que um bit armazena não é relevante para nós. Em programação, 1Byte se refere a um inteiro com sinal de 8 bits (-128 a 127 = 256 dígitos totais). Eles são como qualquer outro tipo de dados em linguagens de programação.
Camadas:
Metal
Bit (1 ou 0)
Byte (8 bits ou 8 1's e 0's)
Kilobyte (1024 bytes ou 2¹⁰ bytes)
Megabytes (1024 kilobytes ou 2²⁰ bytes)
Bytes em Solidity
A maioria das linguagens de programação possui um único tipo de dados para representar bytes. Mas isso é diferente em Solidity. O Solidity permite que você tenha tipos de dados no intervalo de 1 a 32 (byte1 a byte32) dígitos depois do byte, o que representa o tamanho fixo de byte, por exemplo, byte1 representará 1 byte e byte2 representará 2 e vice-versa. Como podemos armazenar valores em nosso contrato inteligente se o próprio valor é maior que um byte? Se ultrapassar um byte, a parte restante precisa ser armazenada em um slot de memória secundário. Os engenheiros se reuniram e deram a isso o termo Endianness, o que significa a ordem em que os bytes são armazenados. Por exemplo, se você estiver tentando armazenar a palavra '0xCoffee' na memória. Você pode fazer isso de duas maneiras diferentes. Uma maneira de armazená-lo é como 0x, co, ff, ee, todos em slots de memória separados, isso é conhecido como o método Big-Endian. Ou você poderia fazer o contrário e armazená-lo como ee, ff, co, 0x, isso é conhecido como o Little-Endian.
Em Solidity, strings e bytes são armazenados no formato Big-Endian (da esquerda para a direita) e os outros tipos de dados, como números e endereços, são armazenados no método Little-Endian (da direita para a esquerda).
Vejamos alguns exemplos.
bytes1 a = "c" Um caractere, que neste caso é "c", ocupa 1 byte. Se quisermos armazenar um valor hexadecimal, precisamos lembrar que um único dígito ocupa 4 bits. Temos um total de 8 bits em 1 byte, então podemos armazenar 2 dígitos em 1 byte, por exemplo, bytes1 a = 0x55 será igual a [01010101] em binário, onde o binário de 5 é 0101. Se quisermos armazenar mais caracteres, precisamos aumentar o número total de bytes que fornecemos. Caso contrário, receberemos um erro. Vejamos outro exemplo em que queremos armazenar todas as letras do alfabeto inglês. bytes26 a = 'abcdefghijklmnopqrstuvwxyz'
Você também deve ter ouvido falar do tipo de dados chamado byte em Solidity. Você usaria bytes para dados brutos de comprimento não especificado e string para dados de string (UTF-8) de comprimento não especificado. Então, por que, onde e quando devemos usar um byte ou uma string? É fato que você economiza gás quando usa um byte em vez de uma string. No entanto, é preciso usar uma string se a sequência de caracteres dentro das aspas que são usadas para definir o valor de uma string for maior que 32 bytes, porque, como já vimos, os bytes têm um limite de 32. Os bytes também são armazenados como
Big-Endian, como os Endians.
E quanto a matrizes e structs?
As matrizes são tipos de dados, mas mais especificamente são estruturas de dados que dependem de outros tipos de dados. Elas armazenam o valor do mesmo grupo juntos e facilita o processamento de dados, como classificação, pesquisa e iteração. A forma como definimos uma matriz em Solidity é:
uint [5] intArray;
As matrizes em Solidity podem ser fixas ou dinâmicas
Matrizes de bytes de tamanho fixo:
Refere-se a uma matriz que possui um tamanho pré-determinado mencionado no momento da declaração. Você também pode criar uma matriz de bytes de tamanho fixo digitando bytes[tamanho]
com o tamanho sendo qualquer número entre 1 e 32. 32 é o máximo porque é um tamanho de memória comumente usado, então faz sentido otimizá-lo porque seria usado com frequência.
Int [5] sum; // matriz de um inteiro com espaço de armazenamento fixo de 5.
Byte[8] name; // matriz de bytes com espaço de armazenamento fixo de 4.
Quando devemos usar uma matriz de bytes de tamanho fixo? Você deve usar isso para palavras que tenham menos de 32 bytes (são muitas palavras). Todas elas poderiam ser valores de bytes[]
em vez de strings. Você deve saber que não pode retornar uma string de um contrato inteligente e usar esse valor em outro. A matriz de tamanho fixo não pode ser iniciada usando a palavra-chave new. Portanto, a única maneira de inicializá-las é inline (em linha).
Int [3] test = [int(3),20,1,4]
Matrizes de bytes de tamanho dinâmico.
Isso pode ser usado quando você não tem certeza qual será o tamanho da palavra. Como vimos acima, especificamos que o tamanho fosse menor que 32, no entanto, com isso, você realmente não sabe qual será o tamanho. Isso deve ser usado em uma instância em que a string de entrada (que é tecnicamente bytes) de outro contrato inteligente precisa ser usada em seu código.
bytes public b1 = " ABC"; //valor atual 0x616263 onde o valor ascii de a é 61, b é 62 e vice-versa
b1.push ("d") //agora a matriz real é abcd e o valor será 0x61626364
Operadores bitwise
Os operadores bitwise são basicamente operações realizadas no nível de bits de um tipo de dados específico. Isso pode ser uma matriz, string, etc. Eles são usados em cálculos numéricos para tornar o processo de cálculo mais rápido. Apesar de serem tão de baixo nível, os símbolos serão bastante familiares se você já usou JavaScript antes.
Comparação:
<, <=, ==, >=, >, !=
Bit:
E (AND): &
OU (OR): |
OU EXCLUSIVO (XOR): ^
NEGAÇÃO: ~
Agora, você provavelmente está olhando para esses símbolos como, por que preciso disso? Honestamente, você pode se safar sem usá-los, mas isso tornará seu código muito mais eficiente em termos de memória, o que é ótimo quando seu único contrato inteligente está gerenciando mais de 1 Bilhão de dólares em cripto em Pools de Liquidez e o gás é usado para cada operação de escrita/mudança de estado.
Começaremos com duas variáveis: a e b. Para seus valores hexadecimais, vamos escolher duas sequências aleatórias: vamos dizer 73 e d2 (use esta ferramenta para alternar entre hex e binário).
bytes1 a = 0x73; // [11100110]
bytes1 b = 0xd2; // [11010010]
-- -- -- -- --
a & b
, E: precisamos de ambos os 1's em uma coluna para obter um 1 na linha de saída
11100110
11010010
11000010 // ⇒ 0xc2
-- -- -- -- --
a | b
, OU: pelo menos um dos bits tem que ser 1 para obter 1 na linha de saída
11100110
11010010
11110110 // ⇒ 0xf6
-- -- -- -- --
a ^ b
, OU EXCLUSIVO: os valores devem ser opostos em uma coluna para obter um 1 na linha de saída
11100110
11010010
00110100 // ⇒ 0x34 (Aliás, se você quiser saber a, basta fazer XOR comparando output com b)
-- -- -- -- --
~ output
, NEGAÇÃO: você está simplesmente invertendo o 1 ou 0
00110100
11001011 // ⇒ 0xcb
-- -- -- -- --
Duas perguntas surgem:
Quando você usaria isso?
Qual é a relevância de seus resultados?
Você usaria isso para um código mais performático, minimizando seus custos de gás otimizando a memória. Os resultados são relevantes porque são o que você enviaria para diferentes contratos ou para suas próprias funções. Dito isso, L2s e Eth2.0 (em breve?) devem tornar isso desnecessário para a maioria dos contratos.
Artigo original escrito por Alifaizanahmad. Traduzido por Paulinho Giovannini.
Top comments (0)