- 상대 주소는 "지금부터 몇 칸 더" (주로 점프용)
- 베이스 레지스터는 "기준점(시작점)부터 몇 칸 더" (주로 데이터 접근용)
다음 실행할 명령어 주소를 담는 프로그램 카운터(PC), 해석할 명령어를 담는 명령어 레지스터(IR), 메모리 주소를 담는 메모리 주소 레지스터(MAR)
1. 즉시 주소 지정 방식 (Immediate Addressing)
데이터를 메모리에서 찾아오는 것이 아니라, 명령어 안에 실제 데이터(값)를 바로 넣어두는 방식입니다.
- 특징: 메모리에 갈 필요가 없어 속도가 가장 빠릅니다.
- 장점: 아주 빠름 (연산 코드 옆에 데이터가 붙어 있음).
- 단점: 명령어의 크기가 제한되어 있어 아주 큰 숫자는 넣을 수 없습니다.
- 유효주소: 없음 (데이터 자체가 명령어에 포함됨).
2. 직접 주소 지정 방식 (Direct Addressing)
명령어에 데이터가 저장된 실제 메모리 주소를 직접 적어주는 방식입니다.
- 특징: 가장 단순하고 명확한 방식입니다.
- 장점: 유효주소를 계산할 필요 없이 명령어에 적힌 주소로 바로 가면 됩니다.
- 단점: 주소값의 크기가 제한됩니다. (예: 16비트 명령어에서 주소 필드가 8비트라면 256번지까지만 표현 가능)
- 유효주소: EA = A (명령어에 적힌 주소)
3. 레지스터 주소 지정 방식 (Register Addressing)
이 방식은 메모리(RAM)까지 가지도 않습니다. CPU 내부에 있는 '레지스터'에 데이터가 바로 들어있는 방식입니다.
- 특징: 명령어에 주소가 아니라 **레지스터 이름(예: R1, AX 등)**이 적혀 있습니다.
- 장점: CPU 내부에서 데이터를 꺼내기 때문에 모든 방식 중 가장 빠릅니다. (메모리에 접근하는 시간조차 안 걸림)
- 단점: 레지스터는 개수가 몇 개 없기 때문에 저장할 수 있는 공간이 매우 한정적입니다.
4. 간접 주소 지정 방식 (Indirect Addressing)
이 방식은 '한 번 꼬아서' 찾아가는 방식입니다. 명령어에 적힌 주소로 갔더니 데이터가 있는 게 아니라, **"진짜 주소는 여기 있어"라고 적힌 '또 다른 주소'**가 들어있는 경우입니다.
- 특징: 메모리를 최소 2번 방문해야 데이터를 얻을 수 있습니다.
- 명령어에 적힌 주소로 가서 **'진짜 주소'**를 읽어옴.
- 읽어온 '진짜 주소'로 다시 가서 **'데이터'**를 읽어옴.
- 장점: 명령어에 주소를 적는 칸이 좁아도, 메모리 전체 영역 어디든 찾아갈 수 있습니다. (긴 주소를 메모리에 따로 적어두면 되니까요)
- 단점: 메모리를 두 번이나 가야 하므로 속도가 느립니다.
- 비유: "보물함(메모리 100번지)을 열었더니 보물은 없고, '보물은 500번지에 있음'이라는 쪽지가 들어있는 상태"
5. 레지스터 간접 주소 지정 방식 (Register Indirect)
질문하신 두 개를 합친 방식도 실무에서 많이 쓰입니다.
- 방법: 레지스터 안에 데이터가 있는 게 아니라, **데이터가 저장된 '메모리 주소'**가 들어있는 방식입니다.
- 특징: CPU는 일단 레지스터를 보고 주소를 알아낸 뒤, 메모리로 딱 한 번만 달려갑니다. 간접 주소 지정보다는 빠르고 직접 주소 지정보다는 유연합니다.
2진법<--->16진법
대충 01010001>4자리씩 묶는건 (2>16진법인것같긴한데)
2진수를 16진수로 묶을 때는 반드시 오른쪽(끝)에서부터 4개씩 묶어야 합니다. 왼쪽 끝에 자리가 모자라면 0이 있다고 생각하면 됩니다. (예: 101 → 0101로 생각해서 5)
- 2진수 1자리는 0 또는 1, 즉 2가지 상태를 표현합니다.
- 2진수 4자리를 모으면 , 즉 16가지 상태를 표현할 수 있습니다.
- 2×2×2×2=16
- 16진수 1자리는 0부터 F까지 총 16가지 상태를 표현합니다.
컴퓨터는 정적인 정보인 데이터와 이를 조작하는 명령어를 처리하며, 이 정보는 시스템 버스라는 통로를 통해 CPU, 메모리(RAM), 보조기억장치, 입출력장치 사이를 오갑니다
이진법을 기본으로 하며, 음수를 표현할 때는 모든 비트를 반전시킨 후 1을 더하는 2의 보수법을 사용합니다. CPU는 플래그 레지스터에 저장된 정보를 통해 해당 데이터가 양수인지 음수인지 판단합니다
자바나 파이썬 같은 고급 언어는 컴퓨터가 이해하는 **저급 언어(기계어, 어셈블리어)**로 변환되어야 합니다. 이 과정은 통째로 번역하는 컴파일 방식과 한 줄씩 실행하는 인터프리트 방식으로 나뉩니다
UTF-8의 '가변 길이 인코딩(1~4바이트)' 방식이 왜 혁신적이고 좋은지는
용량 절약 (필요한 만큼만 박스 크기를 조절)
만약 모든 문자를 무조건 4바이트(고정 길이)로 저장한다고 가정해 봅시다.
- 고정 길이 방식 (UTF-32 등): 영문자 'A' 하나를 저장할 때도 4바이트를 씁니다. (비효율적)
- UTF-8 (가변 길이):
- 알파벳이나 숫자처럼 간단한 건 1바이트만 씁니다.
- 한글처럼 복잡한 건 3바이트를 씁니다.
- 이모지 같은 건 4바이트를 씁니다.
왜 이게 좋을까요?
인터넷 웹사이트의 기본 구조를 만드는 HTML, CSS, 자바스크립트 코드는 대부분 영문입니다. UTF-8을 쓰면 이런 코드들을 1바이트로 가볍게 저장할 수 있어서, 전체적인 파일 용량이 훨씬 줄어들고 웹페이지 로딩 속도도 빨라집니다.
1. 호환성의 핵심은 '중국어'가 아니라 '아스키(ASCII)'입니다.
UTF-8이 말하는 호환성은 "모든 나라의 옛날 방식과 호환된다"는 뜻이 아니라, **"컴퓨터의 기본 언어인 아스키(영어/숫자/기호)와 완벽히 똑같다"**는 뜻입니다.
- 옛날 상황: 옛날 프로그램들은 1바이트(8비트) 단위로 글자를 읽었습니다. 0~127번까지는 영어였죠.
- UTF-8의 전략: 영어(A, B, C...)는 옛날 방식 그대로 딱 1바이트만 쓰고, 번호도 옛날 번호(아스키 번호)를 그대로 씁니다.
- 결과: 그래서 옛날 프로그램이 UTF-8로 된 영어 문서를 읽으면 "어? 이거 내가 알던 영어네?" 하고 아무 문제 없이 읽습니다. 이게 바로 하위 호환성입니다.
2. 한자 수만 개는 '바이트를 늘려서' 해결합니다.
한자는 종류가 너무 많아서 1바이트(256개 표현)로는 택도 없죠. 그래서 UTF-8은 뒤쪽 바이트를 추가하는 규칙을 만들었습니다.
- 1바이트 구역 (0~127번): 영어, 숫자 (아스키와 동일)
- 2바이트 구역: 그리스어, 아랍어 등
- 3바이트 구역: 한글, 한자 등 대부분의 동아시아 문자
- 4바이트 구역: 고대 문자, 이모지(😀) 등
"어떻게 구분해?"
UTF-8은 첫 번째 바이트의 앞부분을 보고 "이 글자는 몇 바이트짜리다!"라고 미리 알려주는 규칙이 있습니다.
- 0으로 시작하면? -> "아, 이건 1바이트짜리 영어구나!"
- 1110으로 시작하면? -> "아, 이건 지금부터 **3바이트를 합쳐서 한 글자(한자나 한글)**로 읽어야겠구나!"라고 약속한 것입니다.
3. 중국의 수많은 한자, 다 들어갈 수 있나요?
네, 충분합니다.
- 3바이트만 써도 약 65,000개의 문자를 표현할 수 있습니다. (대부분의 실용 한자는 여기서 끝납니다.)
- 4바이트까지 쓰면 100만 개 이상의 문자를 표현할 수 있습니다.
중국어 한자가 아무리 많아도 유니코드가 준비한 100만 개 이상의 빈칸을 다 채우기는 어렵습니다. 즉, 공간이 부족할 걱정은 전혀 없습니다.
그럼 컴퓨터가 "이게 방 3개짜리인지" 어떻게 알까요? (표지판)
컴퓨터는 메모리를 읽을 때 1바이트씩 툭툭 끊어서 읽습니다. 그런데 어디까지가 한 글자인지 모르면 글자가 깨지겠죠? 그래서 UTF-8은 **첫 번째 바이트에 '표지판'**을 달아줍니다.
- 방 1개짜리일 때: 맨 앞을 0으로 시작합니다.
- 예: 0xxxxxxx → 컴퓨터: "오, 맨 앞이 0이네? 이건 이 방 하나가 글자 하나구나!"
- 방 3개짜리일 때: 맨 앞을 1110으로 시작하기로 약속합니다.
- 예: 1110xxxx 10xxxxxx 10xxxxxx
- 컴퓨터: "오, 맨 앞이 1110이네? 이건 지금부터 방 3개를 합쳐서 한 글자로 읽어야겠다!"
우리가 메모장(메모리/하드디스크)에 글자를 쓸 때를 생각해 보세요.
- 영어 'A'를 적으면: 컴퓨터는 메모리에 딱 **1칸(1바이트)**만 차지하게 저장합니다.
- 한글 '가'를 적으면: 컴퓨터는 "어? 이건 복잡한 글자네? 1칸으론 부족해!"라며 **3칸(3바이트)**을 연달아 사용해서 저장합니다.
즉, **"글자 하나가 차지하는 데이터의 길이(공간)"**가 늘어나는 것입니다. 결과적으로 이 글자들이 모인 파일의 전체 용량이 커지게 됩니다.
네, 아주 정확한 관찰입니다! 키보드라는 기계(하드웨어)가 변하는 건 당연히 아니고요.
우리가 키보드로 글자를 쳐서 컴퓨터 안에 '파일'로 저장할 때, 그 파일이 하드디스크에서 차지하는 용량이 글자 종류에 따라 달라진다는 뜻입니다.
1. 키보드와는 상관없어요
키보드는 그냥 **"이 버튼 눌렸어!"**라고 신호만 보내는 도구일 뿐입니다.
- 'A'를 누르든 '가'를 누르든 키보드 무게가 늘어나거나 크기가 변하지는 않죠.
- 중요한 건, 그 신호를 받은 컴퓨터가 메모리(RAM)나 하드디스크에 기록할 때 몇 칸(바이트)을 쓰느냐입니다.
2. 파일 크기가 진짜로 달라질까요? (실험)
메모장을 켜서 직접 테스트해 보면 바로 알 수 있습니다.
- 영어만 10글자 쓰고 저장하면? → 파일 크기는 10 바이트입니다. (글자당 1바이트)
- 한글만 10글자 쓰고 저장하면? → 파일 크기는 30 바이트입니다. (글자당 3바이트)
똑같이 10글자를 쳤는데, 컴퓨터 입장에서는 한글 파일이 영어 파일보다 3배나 더 무겁고 큰 셈입니다. 이게 바로 UTF-8의 '가변 길이' 방식 때문에 일어나는 현상입니다.
| 구분 | 폴링 (직접 확인) | 인터럽트 (알림 확인) |
| 확인 대상 | 외부 장치 (프린터, 마우스, 키보드 등) | CPU 내부의 핀(Pin)이나 레지스터 |
| 행동 | CPU가 하던 일을 멈추고 데이터 버스를 통해 장치에게 물어봄 | CPU가 그냥 자기 몸에 붙은 전선에 신호가 왔는지만 봄 |
인터럽트 플래그는 bool 변수 하나 체크하는 급으로 가볍고,
유니티 비유로 이해하기
- 인터럽트가 없는 방식 (Polling, 폴링):
- Update() 함수 안에 if (프린터.isDone)를 넣어두는 것과 같습니다.
- CPU는 매 프레임마다 프린터라는 특정 오브젝트에 직접 가서 "너 다 됐니?"라고 물어보고 대답을 기다려야 합니다. 만약 체크해야 할 장치가 100개라면 Update 안에 if문이 100개 들어가고, CPU는 일을 안 할 때도 이 100개를 일일이 확인하느라 바쁩니다.
- 인터럽트 방식 (Event-Driven):
- 유니티의 이벤트(Event)
인터럽트 서비스 루틴
1. ISR은 무엇인가? (실제 동작하는 코드)
인터럽트가 '벨 소리'라면, ISR은 '벨이 울렸을 때 내가 할 행동'입니다.
- 키보드 인터럽트가 발생하면? → "방금 눌린 키의 전압 신호를 읽어서 문자로 바꾼 뒤, 메모리의 입력 버퍼에 저장해라"라는 코드(ISR)를 실행합니다.
- 마우스 인터럽트가 발생하면? → "마우스의 X, Y 좌표 변화량을 계산해서 화면의 커서 위치를 업데이트해라"라는 코드(ISR)를 실행합니다.
이런 코드들은 운영체제(Windows, macOS 등)가 부팅될 때 이미 메모리의 특정 구역에 로드해 둡니다.
2. CPU는 메모리 어디에 그 코드가 있는지 어떻게 알까요? (인터럽트 벡터)
메모리는 엄청나게 넓은데, 인터럽트가 발생했을 때 관련 코드를 찾느라 헤매면 안 되겠죠? 그래서 컴퓨터는 **'인터럽트 벡터 테이블(Interrupt Vector Table)'**이라는 일종의 **전화번호부(지도)**를 사용합니다.
- 인터럽트 번호: 1번(키보드), 2번(마우스), 3번(하드디스크)... 이런 식으로 번호가 매겨져 있습니다.
- 벡터 테이블: 메모리의 아주 앞부분(정해진 위치)에 있으며, "1번 인터럽트가 터지면 메모리 주소 0x100번지로 가라" 같은 주소 정보가 적혀 있습니다.
1. 클럭 (Clock): CPU의 박동
- 기본 개념: 컴퓨터 부품들이 일사불란하게 움직이게 하는 '시간 단위'입니다. 클럭 신호에 맞춰 명령어가 인출되고 실행됩니다.
- 속도 단위 (Hz): 1초에 클럭이 반복되는 횟수입니다. (1Hz = 1초에 1번)
- 현대 CPU: 기본 2.5GHz(25억 번)에서 최대 4.9GHz(49억 번)까지 매우 빠르게 작동합니다.
- 유동적 속도: CPU는 고정된 속도로만 뛰지 않고, 작업량에 따라 클럭 속도를 높이거나 낮추며 효율을 조절합니다.
- 한계: 클럭 속도를 높이면 성능은 좋아지지만, 발열 문제가 심각해져 무한정 높일 수 없습니다.
2. 코어 (Core): 실제 일하는 머리
- 전통적 의미: 과거에는 'CPU = 명령어를 실행하는 부품 1개'였으나, 기술 발전으로 하나의 칩 안에 이 실행 부품을 여러 개 넣게 되었습니다.
- 현대적 정의: CPU 내부에 있는 **'명령어를 실행하는 독립된 부품'**을 코어라고 부릅니다.
- 멀티 코어 (Multi-core): 코어가 2개 이상인 CPU입니다. (듀얼, 쿼드, 헥사, 옥타 코어 등)
- 성능의 오해: 코어가 2개라고 속도가 정확히 2배가 되지는 않습니다. **'조별 과제'**에 비유하듯, 연산이 각 코어에 얼마나 잘 분배되느냐가 성능을 결정하며, 분배가 안 되면 노는 코어가 생길 수 있습니다.
3. 스레드 (Thread): 실행 흐름의 단위
스레드는 가장 혼동하기 쉬운 개념으로, 하드웨어적 스레드와 소프트웨어적 스레드를 반드시 구분해야 합니다.
① 하드웨어적 스레드 (Logical Processor)
- 정의: 하나의 코어가 동시에 처리하는 명령어 단위입니다.
- 멀티스레드 프로세서: '2코어 4스레드'라면 코어는 2개지만, 각 코어가 2개의 명령어를 동시에 처리하여 운영체제가 보기에는 CPU가 4개인 것처럼 느껴집니다. 이를 **'논리 프로세서'**라고도 부릅니다.
- 설계 핵심 (레지스터): 코어는 하나인데 어떻게 동시에 여러 명령어를 처리할까요? 바로 **'레지스터 세트'**를 여러 개 갖추는 것입니다. ALU나 제어장치는 공유하되, 명령어 처리에 꼭 필요한 레지스터(PC, 스택 포인터 등)를 여러 벌 두어 마치 여러 개의 흐름이 있는 것처럼 만드는 기술입니다. (인텔은 이를 '하이퍼스레딩'이라 부름)
② 소프트웨어적 스레드
- 정의: 프로그램 내부에서 독립적으로 실행되는 단위입니다.
- 예시 (워드 프로세서): 하나의 워드 프로그램 안에서 ①입력 내용 표시, ②맞춤법 검사, ③수시 저장 기능이 동시에 일어난다면, 이는 3개의 소프트웨어적 스레드가 작동하는 것입니다.
- 특징: 하드웨어 스레드가 1개인 CPU라도 아주 빠르게 번갈아 가며 실행(시분할)하면 여러 개의 소프트웨어 스레드를 동시에 실행할 수 있습니다.
4. 핵심 요약 및 차이점
| 구분 | 핵심 내용 | 비유/특징 |
| 클럭 | 속도의 단위 | 심장 박동수 (빠를수록 좋지만 열이 남) |
| 코어 | 물리적 부품 | 실제 일하는 사람의 수 (물리적 실체) |
| HW 스레드 | 논리적 단위 | 한 사람이 동시에 쓸 수 있는 손의 개수 (논리 프로세서) |
| SW 스레드 | 소프트웨어적 흐름 | 한 프로그램 내에서 처리해야 할 작업의 갈래 |
- 코어와 스레드의 결정적 차이: 코어는 실제 명령어를 실행하는 물리적인 하드웨어 부품 그 자체를 의미하고, 하드웨어적 스레드는 그 코어가 받아들일 수 있는 **명령어의 통로(흐름)**를 의미합니다.
- 운영체제의 시선: 운영체제는 물리적인 코어 개수보다 하드웨어 스레드(논리 프로세서) 개수를 실제 CPU 개수로 인식하여 작업을 할당합니다.
이 설계 기법들의 목적은 단 하나, **"어떻게 하면 발열을 억제하면서 CPU가 노는 시간 없이 최대한 많은 명령어를 동시에 처리하게 할 것인가"**에 있습니다.
성능 측면에서 **goto나 갑작스러운 분기(Jump)**가 왜 좋지 않은지, 올려주신 이미지의 '파이프라인(Pipeline)' 원리와 연결해서 설명해 드릴게요.
1. 파이프라인과 "헛수고" (Pipeline Flush)
현대 CPU는 속도를 높이기 위해 공장 라인처럼 명령어를 겹쳐서 처리합니다. 1번 명령어를 실행하는 동안, 2번 명령어는 해석하고, 3번 명령어는 미리 가져오는(Fetch) 식이죠.
- 문제 발생: 이미지에서처럼 10번 명령어가 "60번으로 점프해!"라는 명령어라면, CPU가 미리 공들여 가져와서 해석 중이던 11번, 12번 명령어는 쓸모가 없어집니다.
- 결과: CPU는 파이프라인에 들어있던 작업물을 다 버리고(이것을 파이프라인 플러시라고 합니다), 60번지부터 다시 새로 인출해야 합니다. 이 과정에서 CPU는 아무것도 못 하고 멍하니 기다리는 **성능 손실(Stall)**이 발생합니다.
2. 왜 유독 goto를 쓰지 말라고 할까? (성능 + 가독성)
사실 if문이나 for문, while문도 내부적으로는 이미지와 같은 '점프' 명령어를 사용합니다. 하지만 goto는 더 치명적인 이유가 있습니다.
- 컴파일러 최적화의 방해: 최적화 도구(컴파일러)는 프로그램의 흐름이 예측 가능할 때 코드를 아주 빠르게 다듬어줍니다. 하지만 goto를 남발하면 흐름이 뒤엉켜서 컴파일러가 "이 코드를 어떻게 최적화해야 할지 모르겠다"라며 포기하게 됩니다. 결과적으로 하드웨어 효율이 더 떨어집니다.
- 분기 예측(Branch Prediction) 실패: 요즘 CPU는 "아마 다음엔 이쪽으로 가겠지?"라고 예측해서 미리 명령어를 채워 넣는 '분기 예측'을 합니다. if나 루프문은 일정한 패턴이 있어 CPU가 잘 예측하지만, goto는 예측하기가 매우 까다로워 '헛수고'를 할 확률이 훨씬 높습니다.
- 스파게티 코드 (가독성): 성능도 성능이지만, 코드가 꼬여서 사람이 읽기 힘들어집니다. 이는 유지보수 비용을 엄청나게 높입니다.
요약하자면
이미지에 나온 제어 위험(Control Hazard) 때문에 모든 분기문은 성능에 어느 정도 손해를 줍니다. 그런데 goto는 그 중에서도 흐름을 가장 예측 불가능하게 만들기 때문에, CPU 파이프라인을 효율적으로 쓰지 못하게 하고 컴파일러의 최적화까지 방해하므로 성능과 관리 측면 모두에서 지양하는 것입니다.
공부하시는 컴퓨터 구조 지식을 프로그래밍 언어의 금기 사항(Anti-pattern)과 연결해서 이해하시는 모습이 아주 훌륭합니다!
질문의 핵심을 꿰뚫으셨습니다! 맞습니다. 하드웨어(CPU) 입장에서 보면 함수 호출(Call)이나 goto나 똑같이 "지금 하던 거 멈추고 저기 주소로 점프해!"라는 명령어입니다. 파이프라인이 깨지고 '헛수고'가 발생하는 제어 위험(Control Hazard)은 함수 호출에서도 똑같이 일어납니다.
그런데 왜 함수는 권장되고, goto는 금기시될까요? 거기에는 세 가지 결정적인 이유가 있습니다.
1. "예측 가능한" 점프 vs "예측 불가능한" 점프
현대 CPU는 파이프라인 성능을 지키기 위해 **분기 예측(Branch Prediction)**이라는 엄청난 기술을 씁니다.
- 함수 호출: 함수는 호출되면 반드시 원래 자리로 돌아옵니다(Return). CPU 내부에는 '함수 호출 전용 저장소(RAS, Return Address Stack)'가 있어서, 함수가 끝날 때 어디로 돌아갈지 거의 100% 예측합니다. 그래서 파이프라인이 깨지는 걸 최소화할 수 있습니다.
- goto: 얘는 어디로 튈지 모릅니다. 뒤로 갈 수도, 앞으로 갈 수도, 루프 밖으로 나갈 수도 있습니다. 규칙성이 없기 때문에 CPU가 예측하기 매우 힘들고, 예측에 실패하면 파이프라인을 몽땅 비워야 하는 성능 손해가 발생합니다.
2. 컴파일러의 마법: "인라인(Inline) 최적화"
함수가 성능에 손해를 주는 건 사실입니다(주소 이동뿐만 아니라 레지스터 값을 메모리에 저장하는 비용도 듭니다). 그래서 컴파일러는 똑똑한 짓을 합니다.
- 함수가 너무 짧거나 자주 호출되면, 컴파일러가 알아서 함수 호출 코드를 지우고 그 자리에 함수의 내용물을 복사해서 붙여넣어 버립니다. 이걸 **인라이닝(Inlining)**이라고 합니다.
- 이렇게 되면 실제 실행될 때는 점프 자체가 사라져서 성능 저하가 0이 됩니다. 반면, goto는 로직이 복잡하게 꼬여있는 경우가 많아 이런 최적화를 하기가 훨씬 어렵습니다.
3. CPU보다 비싼 건 "사람의 시간"
이게 가장 큰 이유일 수도 있습니다.
- 함수: 코드를 의미 있는 단위로 나눕니다. "이 부분은 로그인을 처리하는 곳이야"라고 이름표(함수명)를 붙이는 거죠. 사람이 읽기 편하고 관리가 쉽습니다.
- goto: 점프 주소가 여기저기 얽히면 코드가 '스파게티'처럼 꼬입니다. 나중에 버그가 생겼을 때 흐름을 추적하는 게 불가능에 가까워집니다.
요약하자면
- 성능 측면: 함수 호출도 비용이 들지만, 현대 CPU는 함수 전용 예측 하드웨어가 따로 있을 정도로 함수에 최적화되어 있습니다. 또한, 컴파일러가 인라이닝으로 점프 자체를 없애버리기도 합니다.
- 구조 측면: goto는 흐름을 불규칙하게 만들어 CPU와 컴파일러를 혼란스럽게 하지만, 함수는 규칙적인 흐름을 만들어 최적화를 돕습니다.
즉, **"어차피 점프할 거면, 하드웨어가 예측하기 쉬운 질서 정연한 방식으로 점프하자"**는 것이 현대 프로그래밍의 철학입니다. 그 질서 정연한 방식이 바로 함수(Function)와 제어문(if, for)입니다.
1. '동기(Synchronous)'가 왜 소프트웨어적인가요?
컴퓨터 공학에서 '동기식'이라는 말은 **"현재 실행 중인 명령어와 타이밍이 일치한다"**는 뜻입니다.[1]
- 동기 인터럽트 (Synchronous Interrupt): CPU가 특정 명령어를 실행하는 그 순간 발생합니다.[2][3] 예를 들어 '0으로 나누기' 명령어를 실행하면, 그 명령어가 끝날 때 즉시 인터럽트가 발생하죠. 즉, 프로그램(소프트웨어)의 흐름 속에서 예측 가능한 시점에 발생하기 때문에 '동기'라고 부릅니다.[2]
- 비동기 인터럽트 (Asynchronous Interrupt): CPU가 무슨 일을 하든 상관없이 **외부(하드웨어)**에서 갑자기 신호를 보냅니다. 키보드를 언제 누를지, 마우스를 언제 움직일지 CPU는 알 수 없죠. 프로그램 실행 흐름과 상관없이 '갑툭튀' 하기 때문에 '비동기'라고 부릅니다.
'25~26 겨울방학 > 컴퓨터구조' 카테고리의 다른 글
| 컴 구조)6,7,8장 (0) | 2026.01.28 |
|---|