![[Pasted image 20240323012814.png]]
솔리디티에서 데이터를 저장할 수 있는 공간은 총 6개이다. 솔리디티로 코딩하면서 자주 언급되는 개념은 총 stack, memory, storage, calldata 이므로 이 넷에 대해 알아보자.
EVM은 기존 프로세서와 컴퓨터에서 볼 수 있는 레지스터 기반 아키텍처가 아닌 스택 기반 아키텍처이다.
EVM의 스택엔 16진수 32바이트 워드(word)를 단위로 자료가 저장된다.
- 한 워드는 32바이트(256비트)
- 16진수: 0부터 15까지를 09, AF로 표현하는 숫자체계
- 32바이트 워드를 16진수로 표현: 32바이트는 64자리의 16진수로 표현됨
이때 각 항목은 256비트(32바이트) 크기를 가지는데, 이를 16진수로 표현하면 다음과 같다.
0x0000000000000000000000000000000000000000000000000000000000000001 // 0x를 뺴고 64자리
위는 10 진수 1을 나타내는 32바이트 워드이다.
EVM 스택이 이렇게 32바이트 워드 단위로 자료를 저장하는 이유는 다음과 같다. 1. 일관성: 모든 데이터를 동일한 크기로 처리할 수 있음 2. 효율성: 256 비트 단위 연산이 효율적 3. 충분한 표현 범위: 이 방식은 대부분의 데이터와 주소를 표현할 수 있음
스택 상단에 있는 0x로시작하는 정보들은 실제 opcode와 인터랙션을 하게 된다. ![[Pasted image 20240709073709.png]]
memory도 stack과 같이 32바이트 워드 단위로 자료를 저장하지만 차이점은 선입선출 방식으로 동작하지 않는다는 점이다. push on, pop off 같은 연산이 없다. 원하는 메모리 공간에 가서 바로 값을 쓰는게 가능하다.
메모리는 주로 struct를 저장하는데 사용된다.
Calldata와 memory 변수는 함수가 호출되는 동안에만 임시로 존재한다.
Person[] public listOfPeople; // []
function addPerson(string memory _name, unit256 _favoriteNumber) public {
listOfPeople.push(Person(_favoriteNumber, _name));
}
addPerson
이라는 함수를 사용해서 동적 배열에 사람을 추가하려고 하는 경우를 생각해보자. 이때 _name
은 memory 에 저장되기 때문에 함수가 호출되는 동안에만 접근 가능하다.
Person[] public listOfPeople; // []
function addPerson(string calldata _name, unit256 _favoriteNumber) public {
listOfPeople.push(Person(_favoriteNumber, _name));
}
예시에서도 마찬가지이다. _name
은 calldata에 저장되기 때문에 함수가 호출되는 동안에만 접근 가능하다.
대다수의 경우 함수 내 변수는 기본이 memory 변수이다. 그런데 string은 솔리디티에서 특별한 종류의 데이터타입이기 때문에 memory인지, calldata인지 명시해야 한다.
그럼 둘의 차이는 무엇일까? 예시를 살펴보자.
Person[] public listOfPeople; // []
function addPerson(string memory _name, unit256 _favoriteNumber) public {
_name = "cat";
listOfPeople.push(Person(_favoriteNumber, _name));
}
함수를 호출하는 쪽에서 매개변수로 이름을 넘겨줬지만 함수 내부에서 재 할당을 통해 이름을 수정 해보자. 그리고 컴파일 해보면 정상적으로 컴파일된다.
하지만 _name
이 calldata인 경우에 컴파일이 되지 않는다.
이렇듯 memory 변수는 수정이 가능한 반면 calldata는 수정이 불가능하고 읽기만 가능하다. 따라서 가스비 소모가 적다.
따라서 읽기만 필요한 값이라면 당연히 calldata 저장되도록 코딩하는게 좋다.
그럼 storage 변수는 뭐가 다를까? stroage 변수는 유일하게 영구 저장된다. 그리고 수정이 가능하다. 그리고 가장 비싼 데이터 저장 영역이다.
참고로, 영구저장하고자 하는 값은 컨트랙트 가장 최상단에 두어 상태변수로 설정해 영구저장하는게 업계 관례이다.
struct, mapping, array는 memory 키워드랑 같이 나와야 한다(string은 글자의 배열)