본문 바로가기

VEDA 복습

VEDA 1 일차 : C 프로그래밍

반응형

 

한화비전 부트캠프 VEDA 1일차 배운 내용 복습

 

C와 C++의 차이

  • C : 역사가 오래됨, 구조가 간단함( = 구현에 있어서 사용자 부담이 큼), 하드웨어 친화적, 함수형 구조
  • C++ : C에서 파생함, C에 비하여 다소 복잡함( = 구현에 있어서 사용자 부담이 줄어듦, 여전히 부담이 큰 편), 객체 지향형(클래스 지원)

 

프로그램이 만들어지는 과정

전처리 -> 컴파일링 -> 링킹 과정을 거쳐서 소스 코드가 실행 파일로 만들어진다.

 

빈 소스 코드 파일을 컴파일 하고자 시도하면 다음과 같은 메시지가 출력됨.

C:/Program Files (x86)/Dev-Cpp/MinGW64/bin/../lib/gcc/x86_64-w64-mingw32/4.9.2/../../../
	../x86_64-w64-mingw32/lib/
	../lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o): In function `main':
C:/crossdev/src/mingw-w64-v3-git/mingw-w64-crt/crt/crt0_c.c:18: 
	undefined reference to `WinMain

 

gcc 컴파일러의 경우 main 함수를 디폴트 진입점으로 사용한다. main 함수를 작성해주면 해당 error는 사라진다.

또한 gcc의 경우 기본적으로 return 값에 대해서 int가 디폴트이고, 파라미터에 대해서 void가 디폴트이다.

 

 C는 엄밀한 프로그래밍 언어이다. STD 라이브러리에 정의되어 있는 함수일지라도, 정확히 그 함수를 사용한다는 내용을 기재하지 않으면 경고가 발생한다. (-Wall : gcc 컴파일 오류 출력 옵션) 헤더 파일은 특정 형태의 함수, 변수, 상수 등을 사용하겠다고 명확하게 정의해 놓은 파일이다.

 

 전처리자는 컴파일 전 소스 코드를 가공하는 과정이다. #include <stdio.h>라는 전처리 작업은 stdio.h 헤더 파일에 적혀 있는 내용을 모두 포함시키는 것이다. (-E : 전처리 과정 서술 옵션). .h, .c 모두 근본적으로는 텍스트 파일이다.

 

 주소의 데이터 크기는 컴퓨터의 주소 체계에 따라 달라질 수 있다. 예를 들어 32 bit 주소 체계를 가정하고 컴파일링하면 주소를 저장한 데이터의 크기는 4 Byte가 될 것이고, 64 bit 주소 체계를 가정하고 컴파일링하면 8 Byte가 될 것이다. 일반적으로 64 bit 주소 체계를 사용하지만, 경우에 따라서, 특히 임베디드 분야에서 32 bit 주소 체계를 사용하기도 한다.

 

 .bat 파일을 이용하여 컴파일 과정을 좀 더 간소화할 수 있다.

@echo building hello.c
@gcc -m32 hello.c

 -m32 옵션은 32 bit 체계를 가정하고 컴파일링 하라는 뜻이다. (디폴트는 64 bit이다.)

 

-cxx : xx년에 제정된 C 문법을 사용하겠다는 옵션, 대표적으로 ANSI의 C89, ISO의 C90 등을 꼽을 수 있다.

 

#define FUNC(a, b) : MACRO 함수를 만들어 사용할 수 있다.(전처리기가 바꾸어 준다, 가시성을 위하여)

 

변수의 초기화

  • 지역 변수 : 함수 블럭 안에 있는 변수
  • 전역 변수 : 함수 블럭 밖에 있는 변수
  • 자동 변수 : 스택에 잡히는 변수 -> 블럭이 시작되면서 할당되고, 블럭이 끝나면 자동으로 해제되는 변수

***자동 변수는 지역 변수다. 그러나 지역 변수가 반드시 자동 변수는 아니다. ***(ex) static 변수 - 프로그램이 시작될 때 할당되고, 프로그램이 끝날 때 해제된다.) 

  • 글로벌 변수를 초기화하지 않은 경우 : 일반적으로 0으로 초기화 됨
  • 로컬 변수를 초기화하지 않은 경우 : 변수에 대해서 메모리가 할당되었지만 값이 지정되지 않아서 garbage data가 그대로 있음

이러한 차이가 나는 이유는 각 변수가 저장되는 위치가 다르기 때문이다. (objdump -h 명령어를 활용하여 확인할 수 있다.)

  • .text : main, function etc => ROM에 저장(초기) (Build time)
  • .data : global, static variable  => ROM에 저장(초기)  -> RAM으로 복사되어 사용 (Build time)
  • .rdata : read-only data, constant variable -> 읽기만 하는 데이터로 .text에 묻어가는 경향이 있다 (Build time)
  • .bss : non-initialized global variable, non-initialized static variable  => ROM에 저장(초기) -> RAM으로 복사되어 사용 (Build time)
  • stack : local variable, non-initialized local variable (Rum time)
  • Heap : dynamic하게 할당하고 해제할 수 있는 공간  (Rum time)

 실제로 덤핑해서 보면 debug_~~ 형태로 저장공간이 할당된 것을 볼 수 있는데, 디버깅을 위한 정보들을 저장해 놓은 것으로 컴파일 옵션으로 제거할 수 있다.

특정 변수가 어느 저장 공간에 저장되는 지 아는 것은 중요하다. 공간마다 데이터를 읽고 쓰는 권한이 다르다.(스크립트로 지정할 수 있다.) 어셈블리 코드를 보면 더욱 간단하다. (간단하게 문자열을 출력하는 함수) esp는 stack이다.

 

	.file	"hello.c"
	.def	___main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
LC0:
	.ascii "Hello %d\0"
	.text
	.globl	_main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$32, %esp
	call	___main
	movl	$4660, 28(%esp)
	movl	28(%esp), %eax
	movl	%eax, 4(%esp)
	movl	$LC0, (%esp)
	call	_printf
	movl	$0, %eax
	leave
	ret
	.ident	"GCC: (tdm64-1) 4.9.2"
	.def	_printf;	.scl	2;	.type	32;	.endef

 

 

register 옵션 : 우선적으로 레지스터(코어 내에 있음)에 데이터를 할당, &연산자를 사용할 수 없다(주소를 사용할 수 없다.), 메모리 크기는 작지만 SRAM에 있는 데이터의 입출력보다 2배 가량 빠르다 => 자주 접근한 변수에 사용 권장

(ex) register uint32_t example)

 

프로그램 구조와 데이터 출력

함수의 일반적인 형태(C)

void func(arg){ <- Head
	declare		<-Block's Head
	-------
	process		<-Block's Body
	
	return	
}

규칙은 깨졌지만 영향력이 남아있다. 특히 포인터와 연관성이 있다.

 

  • Single type : char(1 Byte), short (2 Byte, half of int) , int (4 Byte, depend on word size, ALU에서 한 번에 끌어 당길 수 있는 사이즈, 명시적으로 할려면 stdtype.h 사용할 것), long(4 Byte, int가 가변적이어서 나온 유닛), float (4 Byte) , double(8 Byte), etc
  • Aggregation  type : struct, union, etc 

signed vs unsigned : 부호 비트의 유무 차이, super 자리가 보통 부호 비트이다.

음수를 구하는 방법 : 모든 비트를 flip하고 일을 더한다. (2의 보수 = 1의 보수 + 1)

 

sizeof() : 함수가 아니라 연산자의 일종이다. 해당 데이터를 저장하기 위하여 몇 바이트가 필요한지 반환한다.

디폴트로 정수형은 int, 실수형은 double로 casting된다.

서로 다른 타입의 변수를 계산할 때는 더 큰 사이즈를 가지는 변수로 casting한다.(컴파일러는 보수적이다.)

***그래서 사칙 연산을 수행할 때 데이터가 소실되는 것을 주의해야 한다.***( 1/2*34 = 0 ?)

 

C에서 지원하는 공식적인 진법은 10진수, 8진수, 16진수이다. 2진수도 지원하지만 과거에는 지원하지 않았기 때문에 사용하지 않는 편이 좋다.

반응형

'VEDA 복습' 카테고리의 다른 글

VEDA 4일차 - C 프로그래밍  (0) 2025.03.20
VEDA 3일차 - C 프로그래밍  (0) 2025.03.19
VEDA 2일차 - C 프로그래밍  (0) 2025.03.18