분류 전체보기 203

C 포인터 배열과 이중 포인터의 메모리 구조

C 언어에서 포인터 배열과 이중 포인터의 관계는 메모리 구조를 이해하는 데 있어 가장 중요한 부분이다.다음 예시 코드를 바탕으로 메모리의 각 영역(Stack, Read-Only Data)에서 데이터가 어떻게 배치되고 참조되는지 분석해보자.#include void print_pointer2(char **p); // *p[]// int main(int argc, char *argv[])int main(){ char *ch2[] = { "Linux", "Windows", "Unix", "Mac", NULL }; print_pointer2(ch2); return 0;}void print_pointer2(char **p) { for(int i=0; p[i] != NULL; i++)..

C언어 배열명과 포인터의 차이: GDB로 문자열 저장 방식 뜯어보기

C언어로 배열을 선언할 때는 문자열을 넣어 초기화할 수 있지만 나중에 배열명에 직접 대입을 해보면 컴파일 에러가 난다.결론부터 말하자면 이는 배열명이 해당 배열의 시작 주소를 가리키는 상수(constant)이기 때문에 다른 주소를 대입할 수 없기 때문이다. 1. 초기화(Initialization) vs 대입(Assignment)C 언어에서 = 연산자는 문맥에 따라 완전히 다른 의미를 갖는다.1️⃣선언 시 초기화: char ch[] = "ABCDEF";이 구문은 변수를 생성함과 동시에 값을 채우는 과정이다.컴파일러는 다음과 같은 작업을 수행한다.메모리(스택 영역)에 7바이트(문자 6개 + NULL) 크기의 공간을 확보한다.확보한 공간에 ch라는 이름을 붙인다.해당 공간에 'A', 'B', 'C', 'D',..

리눅스 스토리지 계층 구조의 이해: 디스크, 파티션, 파일 시스템

리눅스 시스템 관리의 핵심은 물리적 저장 장치를 논리적인 데이터 관리 체계로 변환하는 과정을 이해하는 데 있다.이 포스팅을 통해 헷갈리기 쉬운 디스크, 파티션, 파일 시스템의 개념적 차이를 명확히 하고, 실제 Rocky Linux 환경에서의 파일 시스템 조회 데이터를 가지고 파일 시스템이 어떻게 구성되어 있는지 알아보자.1. 스토리지 관리의 3단계: 디스크, 파티션, 파일 시스템리눅스에서 저장 장치는 세 가지 논리적 단계를 거쳐 준비된다.디스크 (Disk): HDD 또는 SSD와 같은 물리적인 하드웨어 장치 그 자체를 의미한다. 리눅스 커널은 이를 /dev/sda 또는 /dev/nvme0n1과 같은 장치 파일로 인식하며, 이 상태에서는 아직 데이터를 구조적으로 저장할 수 없다.파티션 (Partition)..

C언어 배열 메모리 레이아웃 (feat. GDB)

C 언어에서 배열이 메모리에 어떻게 저장되고 관리되는지 GDB(GNU Debugger)를 실행해서 눈으로 직접 확인해볼 수 있다.1. 배열 코드배열을 사용하지 않았을 때와 사용했을 때의 차이를 보여주는 예제 코드이다.배열을 사용하면 반복문을 통해 효율적으로 데이터에 접근할 수 있다는 장점이 있다.#include int main() { // 배열을 사용하지 않은 경우 int a, b, c, d, e; a = 1, b = 2, c = 3, d = 4, e = 5; // 배열을 사용한 경우 int number[5] = {1, 2, 3, 4, 5}; printf(">>> 반복문으로 배열 출력 2. GDB 디버깅 과정 및 명령어소스 코드 확인 및 브레이크포인트 설정..

/lib : 정적 라이브러리(.a) vs 동적 공유 라이브러리(.so)

리눅스 시스템 프로그래밍의 기초이자, 효율적인 소프트웨어 빌드 전략을 세우기 위해 반드시 이해해야 할 정적 라이브러리(Static Library)와 공유(동적) 라이브러리(Shared Library)의 차이점을 알아보자.1. 라이브러리 결합 방식의 이해라이브러리란 자주 사용되는 함수들을 미리 컴파일하여 모아놓은 파일이다.프로그램이 빌드될 때 이 라이브러리를 어떻게 포함하느냐에 따라 정적과 동적으로 나뉜다.🟣정적 라이브러리 (Static Library, .a)정적 라이브러리는 컴파일의 마지막 단계인 링크(Linking) 시점에 라이브러리 파일 내의 필요한 기계어 코드를 실행 파일에 직접 복사한다.독립성: 필요한 모든 코드가 실행 파일 내부에 포함되어 있어, 실행 환경에 해당 라이브러리가 없어도 단독으로 ..

비트 연산(Bitwise Operation) + 2의 보수 개념

컴퓨터가 데이터를 처리하는 가장 근본적인 방식은 0과 1의 조합인 비트(Bit) 단위의 계산이다.비트 연산은 고수준 언어에서도 성능 최적화, 네트워크 프로토콜 처리, 하드웨어 제어 등에서 필수 요소로 사용된다.1. 비트 연산의 개념과 논리 구조비트 연산은 정수를 2진수로 변환한 뒤, 각 자릿수(Bit)별로 논리 게이트의 원리를 적용하는 방식이다.각 연산자는 고유의 진리표(Truth Table)를 가지며 다음과 같이 동작한다.주요 비트 연산자 정의AND (&): 두 비트가 모두 1일 때만 결과가 1이 된다.OR (|): 두 비트 중 하나라도 1이면 결과가 1이 된다.XOR (^): 두 비트의 값이 서로 다를 때만 1이 된다.NOT (~): 비트의 값을 반전시킨다 (0→1, 1→0).Shift (>): 비트..

C 주소 전달 메커니즘: scanf 원형과 작동 원리, 메모리 구조

C언어에서 scanf 함수를 사용할 때 막연하게 scanf("%d", &data); 식으로 문자열 리터럴과 주소를 인수로 전달하면 된다고 외우기만 했다면 사실 완전히 이해한 것이라고 볼 수 없다. scanf 함수의 원형을 보면 상수 개념과 포인터 개념이 모두 녹아있다.이를 이해하기 위해서는 C언어가 메모리 상에서 문자열과 일반 변수를 어떻게 취급하는지, 그리고 함수의 원형이 요구하는 데이터의 형태가 무엇인지 알아야 한다. 1. 기본 개념: 변수와 상수, 그리고 문자열 리터럴 데이터는 프로그램 내에서 변경 가능 여부에 따라 변수와 상수로 구분된다.변수(Variable): 선언된 메모리 공간의 값이 실행 중에 변할 수 있다.상수(Constant): 한 번 정해진 값을 변경할 수 없다. const 키워드를..

GDB에서 x 명령어로 메모리 분석하기

C 언어에서 문자와 문자열이 메모리에 어떻게 저장되는지 이해하는 것은 시스템 프로그래밍의 기초다.특히 디버거(GDB)를 통해 실제 메모리 주소에 접근하여 바이너리 데이터를 확인하면, 추상적으로 알고 있던 변수들이 물리적으로 어떻게 배치되는지 시각적으로 파악할 수 있다. 오늘 수업에서는 C언어로 프로그램을 작성하고, GDB를 활용해 메모리 구조를 분석하는 것을 배웠다.1. 소스 코드 작성먼저 문자와 문자열 배열을 포함하는 간단한 C 소스 코드를 작성한다.단일 문자 변수와 두 개의 서로 다른 문자열 배열을 선언하고 출력하는 코드다.소스 코드 (gdbchar.c)#include int main(){ char ch1 = 'A'; char message1[] = "ABCDE"; char mess..

C언어 필수 디버깅 도구 gdb 기본 사용법과 16진수 표현 이해하기

리눅스 환경에서 C 언어를 개발할 때 필수 도구 중 하나는 바로 gdb(GNU Debugger)이다.gdb는 메모리 내부를 들여다보고 프로그램 로직 오류의 원인을 파악하는 데 필요하다. gdb의 설치 방법과 기초 사용법을 알아보자.1. gdb란?gdb(GNU Debugger)는 GNU 소프트웨어 시스템을 위한 기본 디버거이다.작성한 소스 코드가 실행되는 동안 내부적으로 어떤 일이 벌어지는지 추적하거나, 프로그램이 비정상적으로 종료되었을 때의 상태를 분석하는 용도로 사용된다.gdb의 기능특정 행(Line)이나 조건에서 프로그램 실행을 중단시킨다.프로그램이 멈췄을 때, 현재 변수의 값이나 메모리 상태를 확인한다.코드의 흐름을 한 단계씩(Step-by-step) 따라가며 로직 오류를 찾는다.VS Code 디버..

C언어 char 배열의 메모리 할당 및 문자열 초기화 메커니즘 (feat. VS Code 디버거)

C언어에서 문자열 배열을 다룰 때, 선언과 동시에 값을 대입하는 것과 선언 후 별도로 대입하는 것은 메모리 관점에서 차이가 있다.VS Code의 디버거를 통해 각 케이스별로 메모리 내부의 쓰레기값과 데이터 배치 과정을 확인해볼 수 있다. 1. 테스트 코드 작성비교를 위해 두 가지 케이스를 구성했다. CASE 1은 선언과 동시에 초기화하는 방식이고, CASE 2는 선언 후 strcpy 함수를 사용하여 값을 대입하는 방식이다.디버거의 변화를 관찰하기 위해 message1[10] 배열 초기화 부분에 중단점(Breakpoint)을 걸어주고 F5로 디버깅을 실행한다.#include #include int main() { // [CASE 1] 선언과 동시에 초기화 char message1[10] = "H..