면접에서 제대로 답변 못한 김에 정리하는 객체 지향 프로그래밍 4가지 특징!

 

객체 지향 프로그래밍 (OOP) 란?

Object-Oriented Promgramming의 약자로, 객체 지향 프로그래밍(OOP)은 데이터를 객체라는 단위로 나누고, 객체 간의 상호작용을 통해 프로그램을 설계하는 방식이다.
캡슐화, 상속, 다형성, 추상화 같은 개념을 활용하여 코드의 재사용성, 유지보수성, 확장성을 높인다.
즉, 현실 세계를 모델링하여 프로그래밍에 적용하는 방법론이다.

 

C++ 예제 코드로 각각의 특징에 대해서 알아보자

 

캡슐화 (Encapsulation)

캡슐화는 데이터와 메서드를 하나의 객체로 묶고 데이터 접근을 제어한다. 이를 통해 외부에서 직접 접근하지 못하게 한다.

  • brand 와 speed는 private로 선언되어 외부에서 직접 접근할 수 없음
  • getBrand와 SetSpeed() 같은 메서드를 통해 데이터를 간접적으로 조작
#include <iostream>
#include <string>

class Car 
{
private: // 외부에서 직접 접근 불가
	std::string brand;
	int speed;

public:
	// 생성자
	Car(std::string b, int s) : brand(b), speed(s) {}

	// getter와 setter로 데이터 접근 제어
	std::string getBrand()
	{
		return brand;
	}

	void setBrand(std::string b)
	{
		brand = b;
	}

	int getSpeed()
	{
		return speed;
	}

	void setSpeed(int s)
	{
		if (s >= 0) // 유효성 검사
		{
			speed = s;
		}
	}

	void display()
	{
		std::cout << "Brand: " << brand << "\n";
		std::cout << "Speed: " << speed << "km/h\n";
	}
};

int main()
{
	Car myCar("Tesla", 120);
	myCar.display();

	myCar.setSpeed(150);
	std::cout << "Updated speed: " << myCar.getSpeed() << "km/h\n";

	return 0;
}

 

상속(Inheritance)

상속은 기존의 클래스의 속성과 동작을 새로운 클래스가 물려받는다.

  • Dog 클래스는 Animal 클래스를 상속받아 eat() 메서드를 사용할 수 있음
  • 상속을 통하여 코드 재사용성을 높일 수 있음
#include <iostream>

class Animal
{
public:
	void eat()
	{
		std::cout << "This animal eats food.\n";
	}
};

class Dog : public Animal // Animal class를 public 상속
{
public:
	void bark()
	{
		std::cout << "This dog barks\n";
	}
};

int main()
{
	Dog myDog;
	myDog.eat(); // 상속 받은 메서드
	myDog.bark(); // Dog 클래스 고유의 메서드

	return 0;
}

": public" 은 public 상속으로  아래와 같이 상속된다.

  • 상위 클래스의 public 멤버는 하위 클래스에서 public으로 상속
  • 상위 클래스의 protected 멤버는 하위 클래스에서 protected로 상속
  • 상위 클래스의 private 멤버는 하위 클래스에서 접근 불가능하지만, 상위 클래스의 메서드를 통해 간접적으로 접근 가능

 

 

다형성 (Polymorphism)

다형성은 같은 인터페이스로 다양한 동작을 구현하는 것을 의미한다.

주로 가상 함수와 오버라이딩을 통하여 구현된다.

  • draw() 메서드는 Shape 클래스의 포인터를 통해 호출되지만 실체 객체 타입 (Circle 또는 Rectangle)에 따라 동작이 달라짐
  • 코드의 유연성과 확장성을 높일 수 있음
#include <iostream>

class Shape
{
public:
	virtual void draw() // 가상함수
	{
		std::cout << "Drawing a shape.\n";
	}
};

class Circle : public Shape
{
public:
	void draw() override // 오버라이딩
	{
		std::cout << "Drawing a circle.\n";
	}
};

class Rectangle : public Shape
{
public:
	void draw() override // 오버라이딩
	{
		std::cout << "Drawing a rectangle.\n";
	}
};

int main()
{
	Shape* myShape; // 기본 클래스 포인터
	Circle myCircle;
	Rectangle myRectangle;

	myCircle.draw();
	myRectangle.draw();

	myShape = &myCircle;
	myShape->draw(); // Circle의 draw() 호출

	myShape = &myRectangle;
	myShape->draw(); // Rectangle의 draw() 호출

	return 0;
}

가상 함수 (Virtual Fucntion)는 기본 클래스(Base Class)에서 선언되며, 하위 클래스(Derived Class)에서 재정의(Override)될 수 있는 함수이다. 재정의하지 않아도 기본 클래스의 구현을 사용할 수 있다.

virtual 키워드를 사용해 선언한다.

 

추상화 (Abstraction)

추상화는 객체의 복잡성을 숨기고 꼭 필요한 부분만 노출하는 것을 의미한다.

C++에는 추상클래스와 순수 가상 함수로 구현할 수 있다.

  • Animal 클래스는 추상 클래스이며, sound()는 순수 가상 함수
  • Dog와 Cat 클래스는 이를 구현하여 자신만의 동작을 정의
#include <iostream>

// 추상 클래스 (순수가상함수 사용)
class Animal
{
public:
	virtual void sound() = 0; // 순수 가상 함수
};

class Dog : public Animal
{
public:
	void sound() override
	{
		std::cout << "Woof! Woof!\n";
	}
};

class Cat : public Animal
{
public:
	void sound() override
	{
		std::cout << "Meow?\n";
	}
}; 

int main()
{
	Animal* myAnimal; // 추상 클래스 포인터
	Dog myDog;
	Cat myCat;

	myAnimal = &myDog;
	myAnimal->sound(); // Dog의 sound() 호출

	myAnimal = &myCat;
	myAnimal->sound(); // Cat의 sound() 호출

	return 0;
}

순수 가상 함수 (Pure Virtual Function)는 C++의 추상 클래스(Abstract Class)에서 사용되는 함수로, 해당 클래스에서 반드시 하위 클래스에서 재정의해야 하는 메서드를 정의할 때 사용한다.

순수 가상 함수는 아래와 같은 형태로 선언된다.

virtual void functionName() = 0;
  • 순수 가상 함수가 포함된 클래스는 추상 클래스가 됨
  • 추상 클래스는 인스턴스화할 수 없음. 즉, 직접 객체를 생성할 수 없음
  • 순수 가상 함수를 정의함으로써, 공통 인터페이스를 제공하고, 해당 인터페이스에서 반드시 구현하도록 강제할 수 있음
  • 순수 가상 함수는 = 0을 사용하여 선언되며, 하위 클래스에서 반드시 재정의해야 함

c언어의 main()은 실행 파일 옵션을 매개 변수로 받을 수 있다.

아래 예제를 보자.

#include <stdio.h>

int main(int argc, char* argv[] )
{
	printf("argument count: %d\n", argc);
	int i = 0;
	while (i < argc)
	{
		printf("argument value[%d]: %s\n", i, argv[i]);
		i++;
	}
	return 0;
}

 

해당 파일의 경로로 가서 파일을 실행시킴과 동시에 옵션을 전달해줄 수 있다.

window에서 실행파일이 있는 경로로 가서 주소창에 cmd를 입력하면 커맨드창을 실행할 수 있다.

 

argv의 0 번째에는 파일이름 나머지에는 전달한 옵션이 저장되어 있는 것을 확인할 수 있다.

'C language' 카테고리의 다른 글

함수포인터  (0) 2024.12.14
변수 키워드 const, volatile  (1) 2024.12.14
변수 키워드 static과 extern  (1) 2024.12.14
전처리지시문, Header Guard  (1) 2024.12.14
c 구조체, 유니온, typedef, 패딩, 비트필드  (0) 2024.12.13

함수 포인터

함수의 이름도 주소이다.

#include<stdio.h>

void Func1(int a) {
	printf("Func1 %d\n", a);
}
int Func2() {
	printf("Func2\n");
	return 10;
}
int main() {

	void (*p)(int);
	p = Func1;
	(*p)(10);

	int (*q)();
	q = Func2;

	printf("%d", (*q)() + 100);

	return 0;
}

구조체 내에서 함수 포인터를 사용하여 아래와 같이 사용한다.

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
	int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *,
			unsigned int flags);
	int (*iterate) (struct file *, struct dir_context *);
	int (*iterate_shared) (struct file *, struct dir_context *);
	__poll_t (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	unsigned long mmap_supported_flags;
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	void (*splice_eof)(struct file *file);
	int (*setlease)(struct file *, long, struct file_lock **, void **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
	void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
	unsigned (*mmap_capabilities)(struct file *);
#endif
	ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
			loff_t, size_t, unsigned int);
	loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
				   struct file *file_out, loff_t pos_out,
				   loff_t len, unsigned int remap_flags);
	int (*fadvise)(struct file *, loff_t, loff_t, int);
	int (*uring_cmd)(struct io_uring_cmd *ioucmd, unsigned int issue_flags);
	int (*uring_cmd_iopoll)(struct io_uring_cmd *, struct io_comp_batch *,
				unsigned int poll_flags);
} __randomize_layout;

 

간단한 예제로 작성해보자

#include <stdio.h>

// 구조체 정의: 함수 포인터를 멤버로 가지는 구조체
struct Hyndrome_operation {
    void (*act1)(int); // 함수 포인터 멤버
    void (*act2)(int); // 함수 포인터 멤버
};

// 함수 선언
void Func1(int x) {
    printf("Func1 : % d\n", x);
}

void Func2(int x) {
    printf("Func2 : %d\n", x);
}

int main() {
    // 구조체 변수 선언 및 선택적 초기화
    struct Hyndrome_operation hyops = {
        .act1 = Func1,
        .act2 = Func2,
    };

    // 함수 포인터를 멤버로 갖는 구조체의 함수 호출
    hyops.act1(10); // Func1 호출
    hyops.act2(20); // Func2 호출

    return 0;
}

'C language' 카테고리의 다른 글

main argument  (1) 2024.12.14
변수 키워드 const, volatile  (1) 2024.12.14
변수 키워드 static과 extern  (1) 2024.12.14
전처리지시문, Header Guard  (1) 2024.12.14
c 구조체, 유니온, typedef, 패딩, 비트필드  (0) 2024.12.13

const

변수에 적용

const는 영어로 constant 상수를 뜻한다

변수에 해당 키워드가 붙으면 값의 변경이 불가능하다.

int main()
{
	const int var1 = 1;
	var1 = 2; // 불가능: const가 붙으면 값의 변경이 불가능하다
	return 0;
}

포인터에 적용

포인터에 사용되면 위치에 따라 의미가 달라짐

포인터가 가리키는 값이 변경 불가능한 경우

const int *ptr = &x;  // ptr은 x를 가리킬 수 있지만, 값을 변경할 수 없음
*ptr = 20;            // 오류! 가리키는 값 변경 불가
ptr = &y;             // OK! ptr이 다른 변수를 가리키는 것은 가능

포인터 자체가 변경 불가능한 경우

int *const ptr = &x;  // ptr은 x를 가리키며, 포인터의 주소를 변경할 수 없음
*ptr = 20;            // OK! 가리키는 값 변경 가능
ptr = &y;             // 오류! ptr의 주소 변경 불가

포인터와 가리키는 값 모두 변경 불가능한 경우

const int *const ptr = &x;  // ptr이 가리키는 값과 주소 모두 변경 불가
*ptr = 20;                  // 오류! 값 변경 불가
ptr = &y;                   // 오류! 주소 변경 불가

 

volatile

최적화를 방해하는 키워드이다. 

컴파일러는 사용하지 않는 쓸모 없는 코드들을 정리한다.

volatile 용도

  • 메모리 주소를 가진 IO 레지스터
    • H/W가 연결된 메모리 주소값은 사용자가 값을 수정하지 않아도 H/W에 의해 변경될 수 있는데, 컴파일러가 최적화 한다고 주소값을 없애버릴 수 있음
  • 인터럽트 핸들러가 값을 변경하는 전역 변수
    • 인터럽트 핸들러가 값을 변경할 수 있다는 것을 컴파일러가 인지 못할 수 있음
  • 최적화에 의해 오류가 발생할 가능성이 있는 변수

'C language' 카테고리의 다른 글

main argument  (1) 2024.12.14
함수포인터  (0) 2024.12.14
변수 키워드 static과 extern  (1) 2024.12.14
전처리지시문, Header Guard  (1) 2024.12.14
c 구조체, 유니온, typedef, 패딩, 비트필드  (0) 2024.12.13

기본적으로 소스파일이 같은 프로젝트에 있어서 컴파일할 때 링킹이 되는 경우 함수는  별다른 추가 코드 작성 없이 공유된다.

아래 코드를 예시로 보자

main.c

int main()
{
	Hyndrome();
	return 0;
}

hyndrome.c

#include <stdio.h>

void Hyndrome()
{
	printf("I am HYndrome\n");
}

 

하지만 변수는 공유되지 않는다.

extern

extern 키워드를 사용하면 변수도 공유할 수 있다.

아래 예시를 보자

main.c

#include <stdio.h>

extern int a = 1;

int main() {
	printf("main1 %d\n", a);
	Hyndrome();
	printf("main2 %d\n", a);
	return 0;
}

hyndrome.c

#include <stdio.h>
int a;
void Hyndrome() {
	//main.c 에서 extern 된 a 값 출력
	printf("Hyndrome1 %d\n", a);
	a = 2;
	printf("Hyndrome2 %d\n", a);
}

활용

header에 extern 변수를 사용하는 경우 

#include만 하면, 누구나 쓸 수 있는 전역 변수가 된다

common.h

#ifndef COMMON_H
#define COMMON_H

extern int globalVariable;

#endif

소스 파일에 extern 변수를 사용하는 경우

내부적으로 전역 변수를 사용할 때 사용

#include "common.h"

void function1()
{
	extern int globalVariable;
}

Static

static은 다양한 곳에 쓰인다.

함수 내 지역 변수 앞 : 전역 변수화

프로그램이 종료될 때까지 변수의 값이 유지되지만 해당 함수 내부에서만 접근이 가능함

#include <stdio.h>

void function1()
{
	static int var1 = 0;
	for (int i = 0; i < 5; i++)
	{
		printf("function1: %d\n", var1++);
	}
}

int main()
{
	function1();
	function1();
	// printf("result : %d\n", var1); 불가능: var는 function1 내부에서만 접근 가능

	return 0;
}

전역 변수 앞 : 다른 소스 파일에서 공유 불가 ( static > extern)

파일 내부에서만 접근할 수 있는 파일 범위(File scope)를 가지게 된다.

다른 파일에서 전역 변수 이름이 충돌하지 않도록 보호한다.

static은 extern 보다 우선 순위를 가진다.

'C language' 카테고리의 다른 글

함수포인터  (0) 2024.12.14
변수 키워드 const, volatile  (1) 2024.12.14
전처리지시문, Header Guard  (1) 2024.12.14
c 구조체, 유니온, typedef, 패딩, 비트필드  (0) 2024.12.13
고정길이 정수 - stdint.h  (0) 2024.12.13

전처리 지시문

MS learn challenge 전처리 지시문

 

전처리기 지시문

자세한 정보: 전처리기 지시문

learn.microsoft.com

https://learn.microsoft.com/ko-kr/cpp/preprocessor/preprocessor-directives?view=msvc-170

#define

매크로 함수라 한다. 단순 치환이 된다.

  • 장점: 함수 호출이 아니므로 실행속도가 빠름
  • 단점: 실제 코드로 변경되므로 코드 사이즈가 늘어남 
#define SUM(a,b) a+b

int main()
{
	int result = SUM(3, 5);
	
	return 0;
}

 

#undef

정의된 매크로를 해제한다.

정의되지 않은 매크로에 해제에 대한 에러가 발생하지 않는다.

다수의 소스파일에서 정의된 매크로를 재정의할 때 사용한다.

#ifdef ~ #endif , #ifndef  ~ #endf

단일 매크로 확인에 적합하다. 간결하고 읽기 쉽다.

#include <stdio.h>

#define RELEASE
// #define DEBUG

#ifdef DEBUG
int main()
{
	printf("debug mode\n");
	return 0;
}
#endif

#ifdef RELEASE
int main()
{
	printf("release version\n");
	return 0;
}
#endif

#if ~ #elif ~ #else ~ #endif

&&, ||, ==, !=, >, < 등 연산 기호를 사용할 수 있다.

#if defined 

#ifdef와 동일하게 사용 가능하다. 

&&, ||, ==, !=, >, < 등 연산 기호를 사용할 수 있어서 다중 조건에 사용 가능하다.

#error

error 메세지를 출력한다.

어떤 장치를 장착할 지 알수 없는 초기 개발 단계에서 초기화 코드를 작성할 때 쓰인다고 한다.

#include <stdio.h> 

#define DEV1
#define MODE 3

#if defined DEV1 && MODE == 3
int main()
{
	printf("success!\n");
}
#elif !defined(DEV1)
#error no device
#else
#error incorrect mode
#endif

 

Header Guard

헤더 파일에서 중복으로 포함되는 것을 방지하기 위한 기법이다.

조건부 컴파일 전처리기 지시자로 헤더 파일이 중복으로 포함되는 것을 방지할 수 있다.

방법 1 - #pragma once

간단하고 사용하기 쉬운 장점이 있다.

사실 현재 대부분의 컴파일러가 지원한다.

하지만 방법 2에 비해서 잘 사용하지 않는다. 그 이유는

  • 방법 2인 #ifndef가 gcc 표준이다 (gcc ver3.4 이전 버전에서 지원 x)
  • 같은 파일이 여러 경로에 있을 경우에 컴파일러가 다른 파일로 인식해서 중복 포함

자바스크립트에서 ; 를 계속 포함하듯 gcc가 워낙 메이저하다보니 잘 사용이 안되는 것 같다.

#pragma once
// 헤더 파일 내용
#include <stdio.h>

void func1();

 

방법2 - #ifndef ~ #define ~ #endif

해당 이름의 매크로가 없을 경우 해당 이름의 매크로를 정의하고 헤더파일을 작성하는 방법이다.

해당 헤더 파일을 다시 부를 경우 해당 이름의 매크로가 있어서 생략되게 된다.

#ifndef HEADER_FILE_H
#define HEADER_FILE_H
// 헤더 파일 내용
#include <stdio.h>

void func1();
#endif // !

 

데이터 신호를 주고 받을 때, 일반적으로 1 byte 단위가 자주 사용된다.

주소는 byte 단위이다. 리틀 엔디안을 잊지 말자!

#include <stdint.h>
#include <string.h>

int main()
{
	uint8_t target[5] = { 0xAB, 0x12, 0x34, 0x56, 0xCD };

	union _Data_
	{
		uint8_t receiveData[5];

		struct {
			uint8_t head;
			uint8_t body[3];
			uint8_t tail;
		}msg;
	}data;

	memcpy(&data, target, 5);

	return 0;
}

 

C 구조체

struct

타입을 모아 새로운 타입을 만드는 문법

c와 c++에서 차이가 있다

  • c에서는 만들고 난 뒤, 한꺼번에 초기화 불가능 (선언할 때는 가능) 
  • c에서는 선언할 때 앞에 struct 붙여줘야 함

기본 문법

struct AB
{
	int a;
	int b;
};

int main()
{
	struct AB ab;

	ab.a = 1;
	ab.b = 2;

	return 0;
}

구조체 초기화는 선언할 때만 가능

구조체 특정 멤버를 선언 시, 선택해서 초기화할 수 있음

구조체를 만들면서 변수를 만들 수 있음

구조체 내부에 구조체를 만들 수 있음 (구조체의 이름은 필요하지 않아서 생략 가능)

 

typedef

기존 타입을 원하는 이름으로 정의해서 사용할 수 있다

아래 예시에서는 struct AB 를 SAB로 typedef 하였다.

위 방식보다는 아래 방식이 더 많이 사용된다

아예 구조체 이름을 생략해버릴 수도 있다

union

생긴 건 구조체와 비슷하지만 멤버끼리 값을 공유한다!

아래 예시를 보자

 

union 안에 있는 두 변수의 시작 메모리 주소가 같은 것을 확인할 수 있다.

주소는 byte 단위로 리틀 엔디안이 적용되는 것을 확인할 수 있다.

 

위 내용을 적용해보자

#include <stdint.h>

#pragma pack(1) // 여기서 부터 패딩 사용 안함
typedef union {
	uint8_t ori[6];

	struct {
		uint8_t opcode;

		uint8_t lba_part1 : 5;
		uint8_t reserved : 3;

		uint8_t lba_part2;
		uint8_t lba_part3;

		uint8_t length;
		uint8_t control;
	} field;
}Node;
#pragma pack(4) // 여기서 부터 패딩 사용

 

#pragma는 뭐고 uint8_t lba_part1 : 5; 뒤에 붙은 ' : ' 는 뭘까 ?

padding에 대한 개념을 알아보자!

padding 

아래 상황을 보자

AB 구조체에서 a 는 char라서 1 byte인데 뒤에 3byte가 비고 b가 오는 것을 확인할 수 있다.

이는 CPU가 값을 편하게 읽을 수 있도록 컴파일러가 padding을 줘서 그렇다.

CPU가 4byte 씩 읽을 수 있다면 아래와 같은 차이가 생긴다.

하지만 여기서 문제가 생기는데 컴파일러마다 padding을 주는 조건이 다르다

따라서 padding을 주지 않도록 설정해주는 매크로가 바로 #pragma이다.

 

uint8_t lba_part1 : 5 에서 :비트 필드(bit-field)의 크기를 지정하는 부분이다.

비트 필드는 구조체의 각 멤버가 1비트 또는 그 이상의 비트 단위로 할당될 수 있도록 합니다.

이렇게 설정할 경우 uint8_t  타입에서 5비트만 사용 하고,

1byte 내에서 5비트만 차지하게 된다

Memory Mapped IO란?

주기억장치들의 일부 주소를 입출력장치에 할당하는 방법으로,

해당 방식은 별도의 하드웨어 신호핀을 두지않고 Address line에 따라 분기하여 하드웨어에 접근하는 방식이다.

특징으로는 

  • 메모리 일부 공간을 I/O 포트에 할당
  • 메모리와 입출력 번지 사이의 구별이 없음
  • 메모리 명령으로 사용 가능
  • 기억장치 이용 효율이 낮고 (I/O 포트가 주소영역을 공유하기 때문에)  H/W가 간단

상대되는 방식으로는 I/O Mapped I/O가 있다

 

 

STM32F103RB 기준으로 확인하기

임베디드 프로그래밍에 사용되는 ARM  프로세서는 memory mapped I/O 방식을 사용한다.

SSAFY 수업에서 사용했던 STM32F103RB 기준으로 설명해보겠다.

 

STM32F103RB 

datasheet에서 Memory mapping 부분을 확인하면 메모리가 어떻게 사용되는지 확인할 수 있다.

주소가 낮은 곳에 시스템과 기억장치가 맵핑되어 있고,

주소가 높은 곳에 입출력관리 및 peripherals(주변장치)가 메모리에 맵핑되어 있는 것을 확인할 수 있다.

 

많은 임베디드 시스템에 사용되는 memory mapped i/o 방식은 메모리에 맵핑된 해당 장치의 레지스터 직접 접근하여 제어한다. 

제어 방법은 referenece manual을 참고하여 해당 레지스터에 값을 입력하는 방식으로 제어할 수 있다.

 

만약 port A의 GPIO를 제어하고 싶으면 referenece manual의 3.3장 Memory map에서 base address를 찾고

원하는 설정 값에 따라서 base address + offset 주소에 설정 값을 넣어주면 제어할 수 있다!

'Computer Science > 임베디드' 카테고리의 다른 글

임베디드 개발 영역  (1) 2024.12.13
유선 통신 기초  (0) 2024.08.19

+ Recent posts