정적 라이브러리와 동적 라이브러리는 프로그램 개발에서
코드의 재사용성과 모듈화를 위해 사용되는 함수를 모아 놓은 실행 파일을 말한다.

 

📌 정적 라이브러리( Static Library )

정적 라이브러리는 실행 파일과 Link타임에 결합되어 한 실행 파일로 합성되는 것을 말한다.

 

특징

  • 파일 확장자
    • .lib
  • 컴파일 및 링크 과정
    • 라이브러리의 소스 코드를 컴파일하여 개별적인 오브젝트 파일( .o 또는 .obj )을 생성한다.
    • 이 오브젝트 파일들을 하나의 정적 라이브러리 파일( .a 또는 .lib )로 묶는다.
    • 프로그램을 빌드할 때 정적 라이브러리를 포함하여 최종 실행 파일을 생성한다.
  • 배포 방식
    • 실행 파일에 라이브러리 코드가 포함되므로, 라이브러리 파일을 별도로 배포할 필요가 없다.
  • 속도
    • 실행 속도가 빠르다. ( 라이브러리가 이미 실행 파일에 포함되어 있기 때문 )
  • 단점
    • 실행 파일의 크기가 커진다.
    • 라이브러리가 변경되면, 모든 프로그램을 다시 컴파일 해야 한다.

 

📌 동적 라이브러리( Dynamic Library )

동적(= 런타임) 라이브러리는 실행 파일과 링크타임에 결합되지 않고 독립적인 실행파일 형태로 생성되며
실행 파일이 실행 될 때 '동적으로' 결합되는 것을 말한다.

 

특징

  • 파일 확장자
    • .dll
  • 컴파일 및 링크 과정
    • 라이브러리의 소스 코드를 컴파일하여 개별 오브젝트 파일( .o 또는 .obj )을 생성한다.
    • 동적 라이브러리( .so, .dll, .dyblib )를 생성한다.
    • 프로그램을 컴파일할 때 라이브러리를 참조하지만, 실행 시점에 라이브러리를 로드한다.
  • 배포 방식
    • 실행 파일에는 라이브러리 코드가 포함되지 않으며, 별도의 동적 라이브러리 파일이 필요하다.
  • 메모리 사용 최적화
    • 여러 프로그램이 하나의 동적 라이브러리를 공유하기 때문에 메모리 사용이 정적 라이브러리보다 효율적이다.
  • 업데이트 용이성
    • 라이브러리를 수정해도 프로그램을 다시 컴파일할 필요 없이 새 라이브러리만 배포하면 된다.
  • 단점
    • 실행 시 라이브러리를 로드해야 하므로 성능이 정적 라이브러리보다 약간 낮을 수 있다.
    • 라이브러리가 없거나 버전이 맞지 않으면 실행 오류가 발생할 수 있다.

📌 구문 분석

어휘 분석을 통해 잘라낸 토큰을 비선형 트리 구조로 그린다.

 

비선형 트리 구조에서 문법 오류를 찾아낸다.

 

while b ≠ 0:
    if a > b:
        a := a - b
    else:
        b := b - a
return a

 

위 코드를 비선형 트리 구조인 Abstract_syntax_tree로 나타내면 아래 그림과 같다.

 

컴파일러는 프로그래밍 언어로 작성된 소스 코드를 기계어로 변환하는 프로그램이다.

 

📌 어휘 분석

컴파일러의 첫 번째 단계를 어휘 분석 또는 스캐닝이라 한다.

 

어휘 분석이란 소스 프로그램을 읽어들여 토큰이라는 의미 있는 문법적 단위로 분리하고 토큰 스트림을 생성하는 것이다.

이러한 어휘 분석을 담당하는 도구를 '어휘분석기' 또는 '스캐너'라고 한다.

 

언어마다 사용하는 토큰이 다르지만 일반적인 프로그래밍 언어에서 사용하는 토큰은 if, for, while과 같은 예약어, 3, 2.5와 같은 상수, +, -, *, /, =와 같은 연산자, 프로그래머가 정의한 식별자, 그리고 괄호나 쉼표(,), 세미클론(;)과 같은 구분자 등이 있다.

 

이러한 토큰은 다음 단계인 구문 분석에서 효율을 높이기 위해 순서쌍( 토큰 번호, 속성 값 )의 형태로 전달한다.

  • 토큰 번호는 모든 토큰을 구별하기 위한 유일한 번호를 말한다.
  • 속성 값은 기호표에 저장된 항목을 가리킨다.
형식 언어란, 인간과 기계 사이에 의사소통을 하는 언어로서 인위적으로 만들어진 언어다.

 

📌 종류

촘스키가 제안한 촘스키 위계에 따라 형식 언어를 네 가지로 계층을 나눠 분류 할 수 있다.

1. 재귀 열거 언어( Recursively Enumerable Language, REL )

🔹 개념

  • 튜링 기계에 의해 인식 될 수 있는 언어다.
  • 모든 계산 가능한 문제가 포함되고, 튜링 기계가 정답을 찾을 수 있는 언어다.
  • 튜링 기계가 항상 멈추는 것은 아니므로, 특정 문자열이 언어에 속하지 않는지 판별하는 것은 불가능 할 수 있다. (즉, 언어에 속하는 문자열은 확인할 수 있지만, 속하지 않는다고 확정할 수 없음)

🔹 특징

  • 가장 강력한 언어 클래스로, 모든 다른 언어를 포함한다.
  • 비결정적 튜링 기계로도 인식이 가능하다.
  • 어떤 문자열이 언어에 속자히 않는지를 결정하는 것은 불가능 할 수 있다. ( 정지 문제와 관련 )

 

형식 언어 중 컴퓨터와의 의사소통에 사용되는 언어를 프로그래밍 언어( = 컴퓨터 언어 )라고 한다.

 

프로그래밍 언어는 사용 목적, 형태와 기능, 세대 등에 따라 여러 가지로 분류할 수 있다.

  • 형태와 기능에 따라 저급 언어와 고급 언어로 나눈다.
    • 저급 언어에는 기계어와 어셈블리어가 있다.
    • 고급 언어에는 C, 파스칼, 코볼 등이 있다.
문자열이란 char 타입의 배열이며, 널 종료 문자(\0)를 포함하는 연속된 문자들의 집합을 말한다.

 

여기서 말하는 배열이라는 것은 그 본질이 메모리의 어느 공간에 저장되어 있는 것이라고 생각할 수 있다.

배열이라면, 그 값을 당연히 수정할 수 있다.

 

실제 코드에서도 char[] 에 문자열을 담고 char[0], char[1], ... 로 접근을 해서 배열의 항목을 수정할 수 있다.

그렇다면 문자열 상수는 어떨까?

#include<stdio.h>

int main()
{
	const char* str = "Hello World\n";
	printf(str);  // 1
	printf("Hello World\n"); // 2

	return 0;
}

위와 같이 str은 문자열 상수로 Hello World 문자열의 주소를 담고 있다.

위와 같은 예제가 있을때 1번 printf에서 중단점을 잡고 디버깅에 진입하고

 

 

str이 있는 메모리 주소로 가면 위 그림처럼 Hello World가 저장되어 있는 것을 볼 수 있다.

 

 

만약 메모리에서 Hello World값을 수정하고 2번 printf에서 Hello World를 출력하면 어떤 값이 출력될까?

 

 

이처럼 2번째 printf에서 TESTING_rld로 바뀐것을 확인할 수 있다.

 

정리해보면 다음과 같다.

1. str이 가리키고 있는 문자열과 2번 printf에서 출력하는 Hello World는 같은 주소다.

2. 문자열 상수라고 하더라도 그 본질은 배열이고 배열이라면 메모리에 연속된자리에 문자들이

저장되어 있는 것이기 때문에 메모리의 값을 수정하면 해당 값이 수정되는 것을 확인할 수 있다.

'CS' 카테고리의 다른 글

[CS] 스택과 힙  (0) 2025.04.09
[CS] 메모리 보호 기법 ( ASLR )  (0) 2025.03.11
[CS] 빅 엔디안, 리틀 엔디안  (0) 2025.02.23
[CS] sleep 함수  (0) 2025.02.11
[CS] 디스패처( Dispatcher )  (0) 2025.02.11
엔디안( Endianness )은 멀티바이트 데이터를 메모리에 저장하는 방식을 의미한다.
컴퓨터는 데이터를 메모리에 저장할 때 바이트 단위로 저장하는데, 
하나의 데이터가 여러 바이트로 구성될 경우 어떤 바이트를 앞에 배치할 것인가에 따라
빅 엔디안과( Big Endian )과 리틀 엔디안( Little Endian ) 방식으로 나뉜다.

 

📌 빅 엔디안( Big Endian )

  • 큰 바이트(= 상위 바이트)를 앞에 배치하는 방식이다.
  • 이 방식은 평소 우리가 숫자를 사용하는 선형 방식과 같은 방식이다.
    • 메모리에 저장된 순서 그대로 읽을 수 있어서 이해하기가 매우 쉽다.
  • RISC CPU 계열에서 이 방식으로 데이터를 저장한다.
  • 네트워크에서 데이터를 전송할 때 사용한다. ( TCP/IP 프로토콜은 빅 엔디안 방식 사용 )

 

📌 리틀 엔디안( Big Endian )

  • 큰 바이트(=상위 바이트)를 뒤에 배치하는 방식이다.
  • 대부분의 x86 아키텍처( Intel, AMD )는 리틀 엔디안을 사용한다.

'CS' 카테고리의 다른 글

[CS] 메모리 보호 기법 ( ASLR )  (0) 2025.03.11
[cs] 문자열 상수  (0) 2025.02.23
[CS] sleep 함수  (0) 2025.02.11
[CS] 디스패처( Dispatcher )  (0) 2025.02.11
[CS] 디자인 패턴  (0) 2024.11.11
  • 1 비트란 '전기 스위치 1개'를 의미한다.
  • 전기가 흐르는 On 상태는 1이다.
  • 전기가 흐르지 않는 Off 상태는 0이다.

📌 2진수, 16진수 진법 변환

2진수(4비트) 16진수
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 B
1100 C
1101 D
1110 E
1111 F
  • 4비트16진수 한 자리 숫자다.
  • 16진수는 0 ~ F( 십진수 15 )까지 한 자리에 쓴다.

📌 16진수 표기가 사용되는 예

  • 색상 표현
  • 컴퓨터 하드웨어 주소 표현
  • 메모리 값 표현

메모리 주소

 

CSS에서 16진수로 색상을 표기한다.

  • 8개 비트를 하나로 묶어 1 바이트( byte )라고 한다.
  • 1 바이트는 영문자 한 글자가 저장될 수 있는 메모리 크기고 관리의 최소단위다.
    • 한글 한 글자를 저장하려면 2바이트가 필요하다.
  • 4비트는 16가지, 8비트는 256가지, 16비트는 65536가지( 64KB )다.
  • 2의 32제곱은 42,9496,7296 ( 약 42.9억 )이다. 42,9496,7296 바이트는 4GB이다.
  • 2의 32제곱은 32 bit를 의미한다. 즉, 32비트 구조상 관리할 수 있는 한계 용량은 4GB다.

📌 컴퓨터 메모리 용량을 말하는 단위

단위 크기 특징
1 Bit( 비트 ) 전기 스위치 1개 용량이 아닌 표현의 최소 수준
1 Byte( 바이트 ) 8비트 한 묶음 영문자 한 글자를 저장할 수 있는 기억 공간의 최소단위다.
( 컴퓨터는 기억공간을 관리할 때 1바이트 단위로 관리한다 )
1 KB( 킬로 바이트 ) 1024 바이트 보통 JPEG 사진 파일 하나가 몇 백 KB 정도 된다
1 MB( 메가 바이트 ) 1024 킬로 바이트 MP3 파일 하나가 대략 4 ~ 5 MB 정도 크기
1 GB( 기가 바이트 ) 1024 메가 바이트 영화(.avi나 .mp4) 파일 하나가 대략 2 ~ 6 GB 정도 크기
1 TB( 테라 바이트 ) 1024 기가 바이트 하드 디스크 1개 용량이 보통 1 ~ 2 TB 정도 크기
1 PB( 페타 바이트 ) 1042 테라 바이트 2016년 7월 기준 네이버 IDC 센터 규모는 약 900 PB 정도
1 EB( 엑사 바이트 ) 1024 페타 바이트 64비트를 용량으로 계산하면 16 EB가 된다
1 ZB( 제타 바이트 ) 1024 엑사 바이트 2017년 기준 전 세계 데이터 센터 트래픽이 약 7.7 제타 바이트다.
1 YB( 요타 바이트 ) 1024 제타 바이트  

 

📌 컴퓨터가 글자를 다루는 방법

  • ASCII( American Standard Code for Information Interchange )는 미국에서 사용하는 표준 코드체계다.
    • 십진수 64 = 'A' = 0x41
  • 숫자와 글자를 구별하지 않고 정보를 말 할때는 바이너리( Binary )라고 한다.

 

📌 컴퓨터가 사진을 다루는 방법

  • 모니터 화면 상 '점' 하나를 화소( Pixel )이라 한다.
  • 여러 점들을 모아 사진을 만들 수 있다.
  • 화소 하나를 표현하는데 8비트, 16비트, 24비트, 32비트 정보가 필요할 수 있다.
  • 빛의 3원색은 Red, Green, Blue다. 이점에 착안해 RGB 컬러가 등장한다.
  • 화소가 작을 수록 사진이 매끄럽다 ( 고해상도 )

x86-64( =x64 ) 아키텍처에서 사용하는 64비트 범용 레지스터는 다음과 같다.

 

레지스터 역할 및 설명
RAX 누산기 레지스터, 산술 및 I/O 연산
RBX 베이스 레지스터, 특정 주소 저장
RCX 카운터 레지스터, 루프 및 반복 연산
RDX 데이터 레지스터, 곱셈 / 나눗셈 연산
RSI 소스 인덱스, 문자열 연산시 사용
RDI 목적지 인덱스, 문자열 연산 시 사용
RBP 베이스 포인터, 스택 프레임 관리
RSP 스택 포인터, 현재 스택 주소
R8 추가적인 범용 레지스터
R9 추가적인 범용 레지스터
R10 추가적인 범용 레지스터
R11 추가적인 범용 레지스터( 일반적으로 임시 저장 용도 )
R12 추가적인 범용 레지스터
R13 추가적인 범용 레지스터
R14 추가적인 범용 레지스터
R15 추가적인 범용 레지스터

 

📌 64비트 레지스터 설명

🌙 연산용 레지스터

🔹 RAX (누산기, Accumulator Register)

  • 산술 연산, I/O 연산, 곱셈/나눗셈 연산에서 기본적으로 사용된다.
  • 함수 호출 시 리턴 값을 저장하는 역할 ( return 값 저장 )

🔹 RBX (누산기, Accumulator Register)

  • 데이터를 저장하는 역할을 하며, 메모리 접근 시 특정 값 저장 가능

🔹 RCX (카운터 레지스터, Counter Register)

  • 루프 및 반복문에서 주로 사용된다.
  • LOOP 명령어에서 반복 횟수를 저장하는 역할을 한다.

🔹 RDX (데이터 레지스터, Data Register)

  • 곱셈/나눗셈 연산에서 사용된다.

 

🌙 메모리 및 스택 관련 레지스터

🔹 RBP (베이스 포인터, Base Pointer)

  • 함수 호출 시 스택 프레임 관리
  • 지역 변수 및 함수 매개변수 접근

🔹 RSP (스택 포인터, Stack Pointer)

  • 현재 스택의 최상위 주소를 가리킨다.
  • 푸시( PUSH ), 팝( POP ) 연산에 사용한다.

 

🌙 문자열 연산

🔹 RSI (소스 인덱스, Source Index)

  • 메모리 복사 시 소스 주소를 저장한다.

🔹 RDI (목적지 인덱스, Destination Index)

  • 메모리 복사 시 목적지 주소를 저장한다.

예제

MOV RSI, source ; 소스 주소
MOV RDI, dest ; 목적지 주소
MOV RCX, length ; 복사할 길이
REP MOVSB ; 바이트 단위로 복사

 

x86 아키텍처에서 사용하는 16비트 범용 레지스터는 다음과 같다.

 

레지스터 설명
AX 누산기, 연산 및 함수 호출 반환값을 저장
BX 베이스, 주소 계산 및 메모리 접근
CX 카운터, 루프 반복 횟수를 저장
DX 데이터, 입출력 및 곱셉 / 나눗셈 연산
SI 소스, 문자열 및 배열 연산
DI 목적지, 문자열 및 배열 연산
BP 베이스 포인터, 스택 프레임 관리
SP 스택 포인터, 현재 스택 위치

 

📌 레지스터의 하위 부분

각 16비트 레지스터는 8비트 단위( AH/AL, BH/BL 등 )로 나뉘어 사용 가능하다.

🔹 AX( 16비트 ) 기준 하위 레지스터 구조

AX ( 16비트 ) = [ 상위 8비트( AH ) | 하위 8비트 ( AL ) ]
  • AX = 누산기 레지스터 전체
  • AH = AX의 상위 8비트
  • AL = AX의 하위 8비트

⭐ 예제( AX를 8비트로 조작 )

MOV AX, 0x1234 ( AX = 0x1234 )
MOV AH, 0x56 ( AH만 변경 ▶ AX = 0x5634 )
MOV AL, 0x78 ( AL만 변경 ▶ AX = 0x5678 )

 

➡️ AX를 8비트 단위로 조작하여 메모리를 절약 가능하다.

 

📌 16비트 레지스터 설명

🌙 연산 및 데이터 관련 레지스터

🔹 AX ( Accumulator, 누산기 레지스터 )

  • 산술 및 논리 연산에서 기본적으로 사용한다
  • I/O 연산, 함수 호출 반환 값을 저장한다.
  • 곱셈( MUL ), 나눗셈( DIV ) 연산에 사용한다.

⭐ 예제 ( AX를 활용한 덧셈 )

MOV AX, 5
ADD AX, 3 ( AX = 5 + 3 = 8 )

 

🔹 BX ( Base Register, 베이스 레지스터 )

  • 메모리 주소 저장
  • 주소 지정에서 베이스 값으로 활용한다.

⭐ 예제 ( 메모리 주소 지정 )

MOV BX, 0x1000 ( 메모리 주소 0x1000을 BX에 저장 )
MOV [BX], AX ( BX가 가리키는 메모리 주소에 AX 값 저장 )

 

🔹 CX ( Counter Register, 카운터 레지스터 )

  • 루프( LOOP ) 및 반복 연산에서 사용한다.
  • 비트 시프트( Shift ) 연산에도 사용한다.

⭐ 예제 ( CX를 활용한 루프 연산 )

MOV CX, 10 ( CX = 10 ( 루프 반복 횟수 지정 )
LOOP_START :
DEX CX ( CX = CX - 1 )
JNZ LOOP_START ( CX가 0이 아니면 루프 반복 )

 

🔹 DX ( Data Register, 베이스 레지스터 )

  • 입출력 포트 접근에 사용한다. ( IN / OUT 명령어 )
  • 곱셈( MUL), 나눗셈( DIV ) 연산 시 사용한다.

⭐ 예제( DX를 활용한 곱셈 연산 )

MOV AX, 5 
MOV DX, 3
MUL DX ( AX = AX * DX ( 5 * 3 = 15 )

 

🌙 문자열 및 메모리 연산 레지스터

🔹 SI ( Source Index, 소스 인덱스 레지스터 )

  • 문자열 복사 및 메모리 접근 시 소스 주소로 사용한다.

🔹 DI ( Destination Index, 목적지 인덱스 레지스터 )

  • 문자열 복사 및 메모리 접근 시 목적지 주소로 사용한다.

 

🌙 스택 관련 레지스터

🔹 BP ( Base Pointer, 베이스 포인터 레지스터 )

  • 스택 프레임을 관리 한다.
  • 함수 호출 시 지역 변수 및 매개변수 접근에 사용한다.

🔹 SP ( Stack Pointer, 스택 포인터 레지스터 )

  • 스택의 현재 위치를 가리킨다.
  • PUSH, POP 연산 시 사용한다.

⭐ 예제( 스택 조작 )

PUSH AX ( AX 값을 스택에 저장 ( SP 감소 )
POP BX ( 스택에서 값을 가져와 BX에 저장 ( SP 증가 )

 

 

✅ 16비트 레지스터는 과거 x86 프로세스에서 사용되었고, 현재는 32비트 / 64비트 레지스터로 확장되었다.

✅ 부트로더, 운영체제 커널, 레거시 코드에서 사용되기 때문에 알아둘 필요는 있다.

+ Recent posts