void 요약(혼공C) {
- C는 UNIX에서 쓰려고 개발;
- 컴파일 =
소스코드
→컴파일러
→기계어
의 과정을 말한다; - 비주얼 스튜디오는 컴파일러의 일종이라고 나와 있다. (내 생각엔 여러 컴파일러를 포함한 IDE 같다.);
- 유용한 단축키 Ctrl+Shift+B(컴파일) Ctrl+F5(실행)
- (소스)전처리(전처리 소스)컴파일(목적파일)링크(실행파일)
}
void 예시(검색 결과, Chat GPT) {
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
이 프로그램은 표준 출력에 "Hello, World!"를 출력합니다. 각 단계별로 파일이 어떻게 변화하는지 살펴보겠습니다.
1. 전처리(Preprocessing) 단계
- 목적: 소스 코드에서
#include
와 같은 전처리 지시문을 처리합니다. 이 단계에서는#include <stdio.h>
같은 지시문이 처리되어 해당 헤더 파일의 내용이 소스 파일에 포함됩니다. - 변화: 전처리기는
#include
지시문을 처리하여stdio.h
의 내용을 포함시킨 새로운 소스 코드를 생성합니다. 사용자가 작성한 코드 외에도 표준 입출력 함수 등의 선언이 추가됩니다. 이 결과는 일반적으로 사용자에게 보이지 않으며, 컴파일러가 내부적으로 처리합니다.
// 예시: 실제로는 stdio.h 내부의 많은 선언들 중 일부만 포함됩니다. int printf(const char *format, ...); int main() { printf("Hello, World!\n"); return 0; }
2. 컴파일(Compilation) 단계
- 목적: 전처리된 소스 코드를 기계어로 번역하는 단계입니다. 소스 코드를 컴퓨터가 이해할 수 있는 오브젝트 파일로 변환합니다.
- 변화: 컴파일러는 전처리된 소스 코드를 분석하여 중간 표현 형태(assembly code)로 변환한 다음, 이를 기계어로 번역합니다. 결과물은
.o
또는.obj
확장자를 가진 오브젝트 파일입니다. 이 파일은 실행 가능한 프로그램이 아니라, 기계어로 번역된 코드의 모음입니다.
// main 함수에서 printf 함수를 호출하는 기계어 코드가 포함되어 있으며, // 실행 가능한 최종 파일을 생성하기 위한 정보와 함께 // 메타데이터, 심볼 테이블 등이 포함 [기계어 코드] [메타데이터] [심볼 및 참조 정보]
3. 링크(Linking) 단계
- 목적: 하나 이상의 오브젝트 파일을 결합하여 실행 가능한 프로그램을 생성합니다. 이 단계에서는 외부 라이브러리 함수 호출(예:
printf
)에 필요한 참조를 해결합니다. - 변화: 링커는 필요한 라이브러리 함수들(예를 들어,
stdio.h
에 정의된printf
)과 사용자가 정의한 오브젝트 파일들을 함께 묶어 실행 가능한 파일을 생성합니다. 결과물은 일반적으로.exe
(윈도우 환경) 또는 단순히 실행 파일(리눅스나 유닉스 환경)입니다. 이 파일은 운영체제가 직접 실행할 수 있는 형태입니다.
//이 파일 내부에는 main 함수와 printf 함수의 실제 코드가 모두 포함되어 있으며, //운영체제가 이해할 수 있는 형태로 구성되어 있습니다. //실행 파일 내부는 대략적으로 다음과 같은 구조를 갖습니다. [프로그램 코드] [라이브러리 함수 코드] [데이터] [실행에 필요한 메타데이터]
이 과정을 통해 간단한 C 프로그램은 사용자가 작성한 소스 코드에서 시작하여 실행 가능한 파일로 변화합니다. 각 단계는 소스 코드를 효율적이고 정확하게 기계어로 변환하는 데 필수적인 역할을 합니다.
void 정리{
1. 전처리: 전처리(preprocessing)는 C 및 C++과 같은 프로그래밍 언어에서 소스 코드가 컴파일러에 의해 컴파일되기 전에 수행되는 초기 처리 단계입니다. 전처리 과정은 전처리기(preprocessor)에 의해 수행되며, 이 단계에서는 주로 매크로 치환, 파일 포함, 조건부 컴파일 등의 작업이 이루어집니다. 전처리기는 소스 코드 파일을 입력으로 받아, 지시어(directives)에 따라 코드를 변환하고, 결과적으로 변환된 코드를 컴파일러가 처리할 수 있는 형태로 출력합니다.
전처리기가 수행하는 주요 작업은 다음과 같습니다:
매크로 치환(Macro Replacement): #define 지시어를 사용하여 정의된 매크로는 소스 코드 내에서 해당 매크로 이름이 나타날 때마다 미리 정의된 코드 또는 값으로 치환됩니다.
파일 포함(File Inclusion): #include 지시어를 사용하여 다른 파일의 내용을 현재 파일에 포함시킵니다. 표준 라이브러리 헤더 파일이나 사용자 정의 헤더 파일을 포함시키는 데 사용됩니다.
조건부 컴파일(Conditional Compilation): #if, #ifdef, #ifndef, #else, #elif, #endif 등의 지시어를 사용하여 특정 조건을 만족할 때만 코드가 컴파일되도록 할 수 있습니다. 이를 통해 플랫폼이나 컴파일러에 특정한 코드를 조건적으로 포함시킬 수 있습니다.
오류 지시와 줄 번호 제어(Error Directive and Line Control): #error와 #line 지시어를 사용하여 컴파일 시 오류 메시지를 생성하거나, 소스 코드의 줄 번호를 제어할 수 있습니다.
프래그마 지시어(Pragma Directives): #pragma 지시어는 컴파일러에 특정한 명령을 내리기 위해 사용됩니다. 컴파일러마다 다르게 해석될 수 있으며, 최적화 옵션 설정 등에 사용됩니다.
전처리 과정은 프로그램의 최종 실행 파일이 생성되기 전 필수적인 단계로, 소스 코드의 가독성, 재사용성, 이식성을 향상시키는 데 도움을 줍니다. 전처리기 지시어는 # 기호로 시작하며, 이는 컴파일러가 아닌 전처리기에게 작업을 지시하는 것임을 의미합니다.
2. 컴파일: 목적파일 생성-CPU이해 가능하지만 os 가 인식할 수 있게 바꿔야.
3. 링크: 목적 파일에 startup code 결합- 프로그램 실행 전 필요한 준비 작업 수행 main함수 호출
C 언어에서 스타트업 코드(startup code)는 프로그램이 실행되기 전 필요한 여러 초기 설정을 수행하는 코드를 말합니다. 이 코드는 프로그램의 실행 파일이 메모리에 로드되고 main
함수가 호출되기 전에 실행되며, 스택 초기화, 전역 변수의 메모리 할당 및 초기화, 표준 라이브러리 및 다른 필수 라이브러리의 초기화 등을 포함할 수 있습니다. C 언어 프로그램의 실행 과정에서 이 스타트업 코드는 컴파일러와 링커에 의해 자동으로 처리되며, 개발자가 직접 작성하는 경우는 드뭅니다.
스타트업 코드는 보통 어셈블리 언어로 작성되어 있으며, 컴파일러나 링커가 제공하는 라이브러리에 포함되어 있습니다. 다음은 C 언어 스타트업 코드가 수행할 수 있는 일반적인 작업들입니다:
- 데이터 세그먼트 및 BSS 세그먼트 초기화: 전역 변수와 정적 변수에 대한 메모리를 할당하고 초기화합니다. 데이터 세그먼트는 초기화된 전역 변수와 정적 변수를 위한 공간을, BSS(Block Started by Symbol) 세그먼트는 초기화되지 않은 전역 변수와 정적 변수를 위한 공간을 갖습니다.
- 힙 및 스택 초기화: 프로그램이 실행되는 동안 동적 메모리 할당과 함수 호출을 위해 사용되는 힙과 스택의 경계를 설정합니다.
- 표준 라이브러리 및 실행 환경 초기화: 표준 입출력 라이브러리 같은 필수 라이브러리의 초기화를 수행하고, 프로그램 실행을 위한 환경을 준비합니다.
main
함수 호출: 모든 초기화 작업이 완료된 후, 스타트업 코드는 프로그램의 진입점인main
함수를 호출합니다.- 프로그램 종료 처리:
main
함수의 실행이 끝나면, 스타트업 코드는 프로그램의 종료 코드를 운영 체제에 반환하고, 필요한 종료 처리 작업을 수행합니다.
C 언어 스타트업 코드는 대부분의 개발자가 일반적으로 접근하거나 수정하지 않는 부분이지만, 내장 시스템이나 특수한 실행 환경에서는 개발자가 스타트업 코드를 직접 조작하거나 커스텀 스타트업 코드를 작성해야 할 수도 있습니다. 이러한 경우, 개발자는 해당 플랫폼의 실행 메커니즘과 하드웨어 세부 사항에 대한 깊은 이해가 필요합니다.
https://kimvampa.tistory.com/27
https://backendcode.tistory.com/161
https://kkhipp.tistory.com/178
GCC(GNU Compiler Collection)와 GNU C는 서로 밀접하게 연관되어 있지만, 각각 다른 역할을 하는 소프트웨어입니다. 간단히 설명하면, GCC는 다양한 프로그래밍 언어를 위한 컴파일러 모음이고, GNU C는 C 프로그래밍 언어를 위한 표준 라이브러리의 구현입니다. 각각에 대해 더 자세히 설명하겠습니다.
GCC (GNU Compiler Collection)
- 정의: GCC는 C, C++, Objective-C, Fortran, Ada, Go, D 등 다양한 프로그래밍 언어를 컴파일할 수 있는 자유-오픈 소스 컴파일러 모음입니다. 원래는 GNU C Compiler로, 오직 C 언어만을 위한 컴파일러였지만, 시간이 지나면서 여러 다른 언어도 지원하게 되어 이름이 GNU Compiler Collection으로 변경되었습니다.
- 역할: 소스 코드를 받아서 기계어로 번역하는 역할을 합니다. 이 과정에서 다양한 최적화를 수행하여 실행 파일의 성능을 향상시킬 수 있습니다.
- 특징: GCC는 다양한 플랫폼에서 사용될 수 있으며, 크로스 컴파일러로도 사용될 수 있습니다. 즉, 한 시스템에서 다른 시스템을 위한 실행 파일을 생성할 수 있습니다.
GNU C
- 정의: GNU C는 GNU 프로젝트의 일부로서, C 표준(예: ISO C99, ISO C11)을 구현하는 C 언어 표준 라이브러리입니다. 이 라이브러리는 glibc(GNU C Library)로도 알려져 있으며, 시스템 호출 래퍼, 기본 데이터 타입, 입출력 처리 등의 기능을 제공합니다.
- 역할: 프로그램이 운영체제와 상호작용할 수 있게 해주며, 파일 조작, 메모리 할당, 문자열 처리 등의 공통적인 작업을 수행하는 함수들을 포함합니다.
- 특징: glibc는 리눅스 기반 시스템에서 가장 널리 사용되는 C 표준 라이브러리 구현 중 하나입니다. POSIX와 같은 표준에 대한 광범위한 지원을 제공하며, GNU 시스템의 핵심 구성 요소 중 하나입니다.
상호 관계
GCC와 GNU C(glibc)는 함께 사용되어 강력한 개발 환경을 제공합니다. GCC가 프로그램의 소스 코드를 컴파일하고, GNU C 라이브러리는 실행 시 필요한 기본적인 인터페이스와 함수를 제공합니다. 예를 들어, printf 함수는 GNU C 라이브러리에 정의되어 있으며, GCC를 사용하여 컴파일된 프로그램은 이 함수를 호출할 수 있습니다.
이 두 소프트웨어는 GNU 프로젝트의 중요한 부분이며, 리눅스를 비롯한 많은 UNIX-like 시스템에서 기본 개발 도구로 사용됩니다.
간단한 C 프로그램의 소스 코드에서 어셈블리 코드로 컴파일된 예제를 보여드리겠습니다. 다음은 아주 기본적인 C 프로그램입니다.
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
이 프로그램을 컴파일하고 어셈블리 코드를 생성하기 위해서는 GCC 컴파일러의 -S 옵션을 사용합니다. 다음은 커맨드 라인 명령어의 예시입니다.
gcc -S main.c
이 명령은 main.c 소스 파일을 컴파일하고, 같은 디렉토리에 main.s라는 어셈블리 코드 파일을 생성합니다. 어셈블리 코드의 정확한 내용은 사용하는 컴파일러의 버전, 타겟 아키텍처, 그리고 컴파일러의 최적화 옵션에 따라 달라질 수 있습니다.
아래는 생성될 수 있는 어셈블리 코드의 간략화된 예시입니다. 실제 코드는 훨씬 복잡하고, 시스템 호출, 레지스터 할당 등을 포함할 것입니다.
.globl main
main:
pushq %rbp
movq %rsp, %rbp
leaq .LC0(%rip), %rdi
call puts
movl $0, %eax
popq %rbp
ret
.LC0:
.string "Hello, World!\n"
이 예시에서는 간단한 “Hello, World!” 프로그램의 어셈블리 버전을 보여줍니다. printf 대신 puts 함수를 호출하는 최적화가 적용될 수도 있습니다. 또한, 이 코드는 특정 아키텍처(예: x86_64)를 대상으로 한 것이며, 다른 아키텍처에서는 다를 수 있습니다.
어셈블리 코드를 이해하고 싶다면, 기본적인 어셈블리 언어와 컴퓨터 아키텍처에 대한 지식이 필요합니다. 어셈블리 코드는 기계어와 매우 밀접하게 연관되어 있으며, 프로세서의 명령어 세트 아키텍처(ISA)를 직접적으로 반영합니다.
'Tech > Coding' 카테고리의 다른 글
C언어 기본] 배열 (0) | 2024.03.22 |
---|---|
🐨그리디 알고리즘 (3) | 2024.03.19 |
10844번 쉬운 계단 수 (0) | 2024.03.03 |
나의 방학 (0) | 2024.03.02 |
가장 가까운 두 점 (0) | 2024.03.02 |