SagiK-Repository / C_Sharp_Deep_Learn

C#을 깊게 배웁니다.
0 stars 1 forks source link

[책] 컴퓨터 시스템 딥 다이브 #27

Open SAgiKPJH opened 3 weeks ago

SAgiKPJH commented 3 weeks ago

0 시작하며

1 C 프로그래밍 언어

char arr[10]; arr[3] = ‘ch’; // arr[3] = lvalue arr = “hello”; // arr, 정적으로 선언된 배열의 기본 주소는 바꿀 수 없다.

struct studentT { int age; } struct studentT student1, student2; student1.age = 18; // age 필드는 lvalue student2.name = student2.name; // 정적으로 선언된 기본 주소는 바꿀 수 없다. name 필드는 lvalue가 아니다.


# 2. C 프로그래밍 심화
- 포인터(pointer)
  - 프로그램 상태 접근을 위한 간접 계층 제공
  - void *는 일반포인터, 모든 타입에 대한 포인터 또는 지정되지 않은 타입을 위한 포인터
    - c 시스템의 메모리 주소가 항상 같은 바이트 수로 저장하기 때문에 일반 포인터 타입을 허용한다.
    - 32비트 -> 4바이트, 64비트 시스템 -> 8바이트
    - 역참조가 불가능하다. 따라서 리캐스팅 필요
    - `array = (int *)malloc(sizeof(int) * 10);`
  - 포인터 변수
    - 특정 타입을 저장할 수 있는 메모리 위치의 주소를 저장
    - 널 포인터를 역참조하면 프로그램에 충돌 발생 위험
    - 포인터(ptr) -> 변수(*ptr)
    - 변수(a) -> 포인터(&a)
  - 포인터 산술
    - 포인터에 값을 더하면 다음 값을 가리킨다. `cptr++;` 
- 동적 메모리 할당(dynamic memory allocation)
  - 프로그래밍이 실행될 때 필요한 공간과 크기를 변화에 맞게 조절해서 필요한 만큼 공간을 할당하고 그 이상 필요하지 않는 공간은 반환
  - 동적으로 할당된 메모리는 프로그램 주소 공간의 힙 메모리 영역을 차지한다.
  - 동적으로 메모리 요청하면 포인터 변수에 해당해야 하는 메모리 청크(chunk)를 제공
  - <img width="285" alt="image" src="https://github.com/user-attachments/assets/7289e89b-10e0-4b5c-847f-0e87934a753e">
- 프로그램의 메모리
  - <img width="279" alt="image" src="https://github.com/user-attachments/assets/ad3d02c8-7780-4b7c-8fc8-c533e1d118d9">
  - 운영체제 이외의 부분은 실행 중인 프로그램에서 사용 가능
  - 지역 변수와 매게변수는 스택(stack)메모리에 상주
  - 전역변수는 데이터 영역에 저장
  - 힙(heap) 메모리 부분은 동적 메모리 할당과 관련된 프로그램 주소 공간의 일부
    - 동적으로 할당되면서 더 높은 주소로 늘려간다.
    - 힙 메모리는 익명 메모리라는 점을 기억하자.
    - 익명이란 힙의 주소가 변수명에 바인딩 되지 않음을 뜻한다.
- malloy과 free
  - 프로그램이 힙에 메모리 할당하고 해제할 수 있게 한다.
  - malloc에 sizeof(<Type>) * count 형식으로 총 바이트 수를 구하는 식으로 전달
  - <img width="285" alt="image" src="https://github.com/user-attachments/assets/0230ebd0-7372-444a-afcb-1a70c834b4de">
  - `[i]`는 메모리에 있는 배열의 기본 주소에서 오프셋 i에 있는 위치를 역참조한다.
- 힙 메모리 관리
  - malloc으로 할당된 힙 공간의 청크 사이에 텅 빈 공간 청크가 생긴다.
  - 힙 메모리 관리자는 메모리 바이트를 할당할 뿐만 아니라 메모리 앞에 몇 바이트 추가로 헤더를 할당한다.
  - 헤더에는 할당된 힙 공간의 청크에 대한 메타데이터가 있다.
  - 이를 활용해 free에는 주소값만 전달해도 해제 가능하다.
  - 힙 메모리 관리자는 전형적으로 특정 크기의 사용 가능한 공간을 빠르게 검색할 수 있도록 힙 내부의 공간들이 갖는 크기를 정리한 목록을 가진다.
- C구조체 (struct)
  - struct 타입은 이종의 데이터 모음(collection)을 나타낸다.
  - 서로 다른 타입으로 이루어진 집합을 하나의 일관된 단위로 취급하는 메커니즘
  - struct를 위한 포인터
```c
struct studentT *sptr;
(*sptr).grad_yr = 2021;
sptr->gpa = 3.5;

infile.txt 파일을 읽기 위해 a.out의 stdin을 리디렉션함

$ ./a.out < infile.txt

outfile.txt 파일을 출력하기 위해 a.out의 Stdout을 리디렉션함

$.1a.out> outfile.txt

a.out의 stdout과 stderr을 out.txt 파일로 리디렉션함

$ ./a.out & outfile.txt

세 가지 모두를 다른 파일로 리디렉션함

(‹stdin, 1› stdout, 2› stderr):

$ ./a.out < infill.txt 1› outfile.txt 2› errorfile.tt


### gcc
- `$ gcc -o myprog myprog.c --static -lpthread -Ireadline`
  - POSIX 스레드 라이브러리(pthread)
와 readline 라이브러리는 gcc 커맨드 라인에서 명시적으로 연결해야 한다.
  - --static 옵션은 정적 연결을 요청하는 한 방법이다.

$ gcc -E myprog.c $ gcc -E myprog. c › out $ vim out

- 프리컴파일러(precompiler) 단계가 먼저 실행 되어 전처리기 지시문을 확장 한다
- 프리컴파일러 단계의 중간 결과를 보려면 gcc에 -E 플래그를 전달한다

$ gcc -S myprog. c $ vim myprog.s

- 컴파일 단계는 컴파일 작업을 수행 하며 기계 없앰 불리 코드로 변환 한다 gcc에 -S 플래그를 전달 한다

$ gcc -c myprog.c $ objdump -d myprog.o

- 어셈블리 단계는 어셈블리 코드를 재배치 가능한 2진 객체 코드(myprog.o)로 변환한다.
  - 기계어 명령을 포함하지만 자체적으로 실행할 수 있는 완전히 실행 가능한 프로그램은 아니다.
- 바이너리 파일(*.o)은 objdump같은 툴을 사용해 표시 가능

$ gcc myprog.c $ ./a.out # a.out의 결과 파일인 .a

$ objdump -d a.out

- 링크 편집 단계는 실행 가능한 단일 파일(a.out)을 생성
  - 재배치된 바이너리(*.o)와 라이브러리(.a 또는 .so)에서 생성된다.
  - 결과파일인 .a에서 라이브러리 함수 사본을 포함한다.
  - 애플리케이션에 의한 모든 라이브러리 함수 호출은 라이브러리 함수가 복사되는 a.out 위치에 바인딩된다. (함수 이름을 메모리 주소로 대체한다)
  - 동적 라이브러리 연결시 사본을 포함하지 않고, 런타임 시 추가 연결 단계가 있다.

$ ldd a.out


- ldd 유틸리티는 실행 파일의 공유 객체 종속성을 나열한다.
- c에서 라이브러리 생성
  - 헤더파일 : 라이브러리에 대한 인터페이스 정의
  - .c파일 : 라이브러리의 구현체 생성
- C를 어셈블리로 컴파일 
  - `gcc -m32 -S simple ops.c`
    - -m32(32비트 버전) 커맨드 라인 옵션을 사용해 IA32 어셈블리 생성을 지정해 IA32 어셈블리 텍스트 파일 (.s)로 컴파일
  - `vim simpleops.s`
  - `gcc -m32 -c simpleops.s`
    - 재배치 가능한 객체 바이너리 파일(.o)로 컴파일
  - `gcc -m32 -o simpleops simpleops.o`
    - 32비트 실행 파일 생성
  - `objdump -d simpleops.o`
    - 매핑하는 기계 코드와 어셈블리 코드를 출력
- 어셈블리 코드
  - 다양한 시스템에서 컴파일과 실행이 가능한 고급 언어인 C와 달리
  - 어셈블리 코드는 저수준 언어이며 특정 하드웨어 아키텍처를 지정한다.
  - 운영체제의 코드 일부는 종종 어셈블리 코드로 구현된다.
SAgiKPJH commented 2 weeks ago
SAgiKPJH commented 1 week ago

3 C 디버깅 도구