학습 자료 글/컴퓨터시스템

컴퓨터시스템 기초 12. 배열과 구조체는 어셈블리에서 왜 주소 계산이 될까

cedis 2026. 3. 31. 16:23

[컴퓨터 시스템] 12. 배열과 구조체는 어셈블리에서 왜 주소 계산이 될까

고수준 언어에서는 `arr[i]`나 `s.field`가 자연스러운 문법처럼 보입니다. 하지만 저수준으로 내려오면 결국 둘 다 '기준 주소에서 얼마나 떨어진 위치를 읽고 쓰는가'라는 주소 계산 문제로 보이기 시작합니다.

이번 글은 배열, 포인터, 구조체를 다시 한 번 어셈블리 관점으로 묶어 보면서, 왜 메모리 배치 감각이 중요했는지 연결합니다.

먼저 짚고 갈 용어
base address: 어떤 데이터 묶음이 시작되는 기준 주소
offset: 기준 주소에서 얼마나 떨어져 있는지 나타내는 값
layout: 메모리 안에 데이터가 배치되는 구조
이번 글에서 다루는 것
  • 배열 인덱싱이 주소 계산으로 보이는 이유
  • 구조체 필드 접근이 offset 문제로 읽히는 이유
  • 자료형 크기가 주소 계산에 왜 들어가는지
  • 포인터와 배열 감각이 여기서 어떻게 다시 쓰이는지
  • 메모리 레이아웃을 눈으로 읽는 연습 문제
한눈에 보는 흐름
1
배열 인덱싱이 주소 계산으로 보이는 이유
2
구조체 필드 접근이 offset 문제로 읽히는 이유
3
자료형 크기가 주소 계산에 왜 들어가는지
4
포인터와 배열 감각이 여기서 어떻게 다시 쓰이는지

1. 배열 접근은 기준 주소 + 간격 계산으로 바뀐다

배열은 연속된 메모리라는 점이 핵심입니다. 그래서 `arr[i]`는 추상적인 문법이 아니라 기준 주소에서 i칸 떨어진 위치를 찾는 계산으로 이해할 수 있습니다.

그림으로 먼저 보기
arr[i]
저수준 질문: 기준 주소에서 i * 원소 크기만큼 떨어진 곳은 어디인가
p + i
저수준 질문: 현재 주소에서 몇 바이트 움직여야 하나

여기서 중요한 것은 i만이 아니라 원소 하나의 크기입니다. int 배열과 char 배열은 같은 i라도 실제 주소 간격이 다릅니다.

표현저수준 질문
arr[i]기준 주소에서 i * 원소 크기만큼 떨어진 곳은 어디인가
p + i현재 주소에서 몇 바이트 움직여야 하나

2. 구조체 필드는 이름이 아니라 offset으로 보인다

구조체는 필드 이름으로 접근하지만, 메모리 안에서는 결국 각 필드가 시작 기준에서 몇 바이트 떨어져 있는지가 중요합니다. 그래서 구조체 접근은 기준 주소 + 필드별 offset으로 읽을 수 있습니다.

그림으로 먼저 보기
구조체 시작
저수준 감각: base address
필드 위치
저수준 감각: field offset
필드 접근
저수준 감각: base + offset 읽기/쓰기

즉 `s.age` 같은 표현도 저수준에서는 's 시작 주소에서 age 필드 offset을 더한 위치'라는 질문으로 풀립니다.

구조체 요소저수준 감각
구조체 시작base address
필드 위치field offset
필드 접근base + offset 읽기/쓰기

3. 자료형 크기가 주소 계산에 끼어드는 이유

초반에는 인덱스만 바뀌는 것처럼 보이지만, 실제 주소 계산에서는 자료형 크기가 꼭 들어갑니다. 4바이트 int 배열에서 다음 원소는 1바이트 뒤가 아니라 4바이트 뒤에 있기 때문입니다.

그래서 배열과 포인터를 읽을 때는 항상 '이 타입 하나가 몇 바이트인가'를 함께 떠올리는 습관이 좋습니다.

3편과 연결되는 감각
포인터 연산이 단순히 숫자 하나를 더하는 일이 아니라 타입 크기를 반영한 주소 이동이라는 점이 여기서 다시 중요해집니다.

4. 조금 더 현실적인 코드 예제를 보자

이 코드에서 저수준 질문은 두 가지입니다. `p->y`는 구조체 시작 주소에서 어느 offset을 읽는가, `arr[i]`는 기준 주소에서 얼마만큼 이동한 뒤 읽는가입니다.

C
struct Point {
    int x;
    int y;
};

int sum(struct Point *p, int i, int *arr) {
    return p->y + arr[i];
}
읽는 순서
구조체면 base + field offset, 배열이면 base + index * element size라는 두 문장을 먼저 떠올리면 됩니다.

5. 직접 해볼 문제: 메모리 레이아웃을 글로 설명해 보자

어셈블리 문법을 몰라도 충분히 풀 수 있는 문제입니다. 핵심은 이름을 주소 계산 문제로 바꾸는 연습입니다.

미니 문제
`char buf[8]; buf[3] = 1;` 과 `struct Pair { int a; int b; }; pair.b = 7;` 를 비교할 때, 두 문장이 각각 어떤 기준 주소와 offset 계산을 요구하는지 글로 설명해 보세요.

이번 글에서 기억할 것

배열과 구조체 접근은 결국 기준 주소에서 얼마나 떨어진 위치를 읽고 쓰는가의 문제다.
인덱스뿐 아니라 자료형 크기와 필드 offset이 주소 계산에 직접 들어간다.
이 감각이 잡히면 어셈블리의 메모리 접근이 훨씬 덜 추상적으로 보인다.

스스로 점검

배열 접근이 왜 base + index * size 계산으로 읽히는지 설명할 수 있는가
구조체 필드 접근을 base + offset 관점으로 설명할 수 있는가
포인터 연산에 자료형 크기가 왜 들어가는지 말할 수 있는가

다음 글 예고

다음 글에서는 x86-64와 ARM64를 비교하면서, ISA가 달라도 우리가 붙잡아야 할 핵심 공통 감각이 무엇인지 정리합니다.

한 줄 정리
배열과 구조체를 저수준에서 읽는 핵심은 이름을 기준 주소와 offset 계산 문제로 바꾸어 보는 데 있습니다.