함수 포인터는 반환형+(*함수이름)+인자로 이루어진다. 함수 이름을 진한색으로 표시한 이유는 단순 함수 이름이 아니라 (*)의 함수 이름이기 때문이다.


printf의 함수 원형(프로토타입) 

int printf (const char*, ...);

↓↓↓↓

타입 추출 (함수 이름만 제거)

int () (const char*, ...);

↓↓↓↓

int (*) (const char*, ...);

symbol table로 나타내면 

 반환형

함수 이름 

 주소

 int (*) (const char*, ...)

printf 

?? 


즉, printf의 함수 타입을 추출해 보면 int (*) (const char*, ...);란 결과를 얻을 수 있다.


자 그럼 내가 만든 함수에서 return 값으로 printf 함수 자체를 반환하면 어떻게 함수 구현을 해야 할까?

일단, 함수의 기본을 보면 예를 들어서 인자는 없고 int형 test함수를 만들고 싶다고 생각했다면 int test(void) { ~~~}를 떠올릴 수 있다. 여기서 반환형은 int, 함수 이름은 test, 인자는 (void) 이다. 

방금 printf 함수의 반환형 int (*) (const char*, ...)라고 하였다. 그렇다면 return printf을 하여서 나오는 반환형은 저 부분이 되어야 하니까 

int (*) (const char*, ...) { ~~ return printf } 가 되게 된다. 여기서 함수 이름을 test로 한다고 하면

int (*test (void)) (const char*, ...) {~~ return printf }

여기서 test(void) 함수 대신 뭐 p를 쓴다던가 단순 변수를 쓰게 되면 그냥 변수가 돼버린다. 주의!!!


이렇게 printf 함수를 반환하는 test함수를 만들었다면, 이걸 main에서 호출해 보자. 방금 만든 test함수의 원형을 살펴보면

맨 처음에 했던 타입 추출하는 방법대로 함수 이름 부분을 (*)로 바꿔주면 된다.

즉, int (*(*)(void)) (const char*, ...) 가 함수 타입 추출이다. 그렇다면 여기에 call이란 함수 포인터 변수를 만들어 준다면?

int (*(*call)(void)) (const char*, ...)

int main()

{

    int (*(*call)(void) (const char*, ...);

    call = test;

}

이렇게 해주면 main에서 내가 만들어준 함수인 test를 호출하고 test함수에서 printf 함수를 리턴하는 것까지 에러, 경고 없이 컴파일이 된다.

'언어 > 큐브인턴(Embedded)' 카테고리의 다른 글

풀업 저항, 풀다운 저항, 플로팅  (0) 2016.08.31
Little Endian, Big Endian  (0) 2016.08.25
리눅스 ASLR 해제  (0) 2016.08.17
C언어 컴파일 과정  (0) 2016.08.16
컴퓨터 구조(CPU, 메모리, 버스) 특강  (0) 2016.08.03
Posted by 知彼知己百戰不殆
,

ㅎㅎ

http://kkamagui.tistory.com/861

https://bpsecblog.wordpress.com/2016/05/16/memory_protect_linux_1/

참고

Posted by 知彼知己百戰不殆
,

컴파일 과정

비주얼 스튜디오 = IDE (통합개발환경) == 에디터, 컴파일러, 에디터

Posted by 知彼知己百戰不殆
,

MCU (Micro Controller Unit) : 마이크로프로세서와 입출력 모듈을 하나의 칩으로 만들어져 정해진 기능을 수행하는 컴퓨터

개인용 컴퓨터(PC)가 다양한 요구에 따라 동작하는 일반적인 일에 사용된다면, MCU는 기능을 설정하고 정해진 일을 수행하도록 프로그래밍되어 장치 등에 장착되어 동작한다. MCU는 임베디드 시스템에 널리 사용된다.


Central Processing Unit (CPU-중앙처리장치) 3대 구성요소

1. Arithmetic Logic Unit (ALU) :  두 숫자의 산술연산(덧셈, 뺄셈 등)과 배타적 논리합 xor, 논리곱, 논리합같은 논리연산을 계산하는 디지털 회로이다. 산술논리장치(ALU)는 컴퓨터 중앙처리장치의 기본 설계 블록

2. Register (Processor Register) : 컴퓨터의 프로세서 내에서 자료를 보관하는 아주 빠른 기억 장소이다. 일반적으로 현재 계산을 수행중인 값을 저장하는 데 사용된다. CPU랑 속도는 동급으로 두는 메모리. 레지스터의 크기는 버스의 크기와 동일.

3. Control Unit (CU) 프로세서의 조작을 지시하는 컴퓨터 중앙처리장치(CPU)의 한 부품이다. 입출력 장치 간 통신 및 조율을 제어한다. 명령어들을 읽고 해석하며 데이터 처리를 위한 시퀀스를 결정


프로그램의 실행 순서:

하드디스크의 .exe파일 -> SRAM -> 주소를 Register가 받아서 -> ALU 나 CU -> 실행


MCU는 CPU보다 확장성이 떨어진다. MCU 안에는 CPU + 여러 칩(RAM, ROM)들이 들어가 있기 때문에. CPU는 메모리가 필요 없으면 메모리를 빼면 되고, 필요하면 꽂으면 되니까 확장성이 좋다.

플래시 메모리 : 전기적으로 데이터를 지우고 다시 기록할 수 있는 비휘발성 컴퓨터 기억 장치. EEPROM과 다르게 여러 구역으로 구성된 블록 안에서 지우고 쓸 수 있다. 

플래시 메모리의 종류

구분

NAND 타입

NOR 타입

용도

USB 메모리, SSD 등 저장 매체

RAM처럼 실행 가능한 코드 저장

읽기

랜덤 액세스이나 한 블록이 모두 동작함. 비교적 느림

셀 단위 랜덤 액세스. 빠름

쓰기

한 번에 한 블록을 통째로 기록하여 빠름

한 셀씩 기록하여 느림

밀도

고밀도

저밀도

가격(용량 대비)

저가

고가

버스의 크기 = 몇 bit 컴퓨터

(ex. 버스의 크기 32bit -> 32비트 컴퓨터)

RAM의 주소(번지)를 관리하는 것이 바로 포인터

부산(CPU)에서 서울로 처음에 주소값(ex.0110)을 보내고 데이터로 1111 1010을 보냄. 그러면 서울(RAM) 6번지(0110)에 처음에 4bit 1111을 받고, 그리고 두 번째로 1010을 받음(버스가 4bit여서 한 번에 4bit만 전송 가능). RAM의 1번지당 크기는 1byte(8bit)로 잡음. 따라서 6번지에 들어가는 값은 1111 1010.


반도체 : 한쪽으로만 전류가 흐를 수 있도록 만든 것. (ex. 다이오드, 트랜지스터)

도체 : 전류가 아무렇게 흐를 수 있도록 만든 것

부도체 : 전류가 흐르지 않게 만든 것


하드디스크를 대신해서 나온 것 : SSD (Solid State Disk)

SSD는 DRAM 휘발성 메모리나 NAND 플래시 비휘발성 메모리로 이루어져 있다.

'언어 > 큐브인턴(Embedded)' 카테고리의 다른 글

Little Endian, Big Endian  (0) 2016.08.25
함수 포인터 (printf함수의 원형과 함수 포인터 사용)  (0) 2016.08.23
리눅스 ASLR 해제  (0) 2016.08.17
C언어 컴파일 과정  (0) 2016.08.16
I2C communication  (0) 2016.08.02
Posted by 知彼知己百戰不殆
,

I2C write

I2C 통신 시 Device Address를 보내고 나서 First Address와 Second Address를 보내고 나서 DATA를 보내야 함. 

그래서 코드 작성 시

#include "mbed.h"

#define ADDR (0xA0)  // 이렇게 Device Address를 16bit로 정해주고

I2C i2c(PB_9, PB_8);

int main() {

char data[3];

data[0]=0x01; // first word address

data[1]=0xAA; // second word address

data[2]='A' // 보낼 데이터

i2c.write(ADDR, data, 3); 

}

I2C read

current address read는 아직 current address를 모른다. 그러므로 current address를 정해주어야 한다.

random read는 device address(1byte) 다음에 1st address(1byte)와 2nd address(1byte) (current address - 2byte)를 write 해주고 나서, read를 해야 한다. (current address = dummy write = dummy byte)

write-read 과정: write(device address, data, byte)로 데이터 보냄 -> read 전에 write(device address, current address, byte)로 address를 보냄 -> read(device address, buffer, byte)로 데이터 읽어들임

read 할 때 write 과정이 없이 바로 read를 하게 되면 current address가 없으므로 데이터를 제대로 못 읽어온다.

Posted by 知彼知己百戰不殆
,

전처리문

언어/C 2016. 5. 2. 14:03

전처리문 : 실질적인 컴파일 이전에 미리 처리되는 문장, 컴파일러는 사용자가 작성한 코드를 컴파일하기 전에 전처리문에서 정의해 놓은 작업들을 먼저 수행함

기존의 방대한 소스 코드를 지우지 않고 활성/비활성 하는 데에 가장 많이 이용된다. 기존의 소스 코드를 건드리지 않는 상태에서 부분적인 컴파일!


- 파일 처리 전처리문 : #include

- 형태 정의 전처리문 : #define, #undef

- 조건 처리 전처리문 : #if, #ifdef, #ifndef, #else, #elif, #endif

- 에러 처리 전처리문 : #error

- 디버깅 전처리문 : #line

- 컴파일 옵션 처리 전처리문 : #pragma


조건 처리 전처리문은 어떤 조건에 대한 검사를 하고 그 결과를 참(0이 아닌 값) 또는 거짓(0)으로 돌려준다.

#if : ...이 참이라면

#ifdef : ...이 정의되어 있다면

#else : #if 나 #ifdef에 대응된다

#elif : "else + if"의 의미

#endif : #if, #ifdef, #infdef 이 끝났음을 알림


#include

 #include <stdio.h>        /* 이 위치에 stdio.h라는 파일을 포함시킨다. */

 #include "text.h"           /* 이 위치에 text.h라는 파일을 포함시킨다. */

 

'<...>'를 사용할 때와 '"..."'를 사용할 때의 차이점은 '<...>'는 컴파일러의 표준 포함 파일 디렉토리(또는 사용자가 별도로 지정해 준)에서 파일을 찾는 것을 기본으로 한다.  그리고 "..."'를 사용했을 때는 현재의 디렉토리를 기본으로 파일을 찾게 된다. 아예 디렉토리를 같이 지정할 수도 있다.


  #include <C:\MYDIR\MYHEAD.H>

  #include "C:\MYDIR\MYHEAD.H"


#define

상수값을 지정하기 위한 예약어로 매크로라고 부른다. 구문의 상수로 치환한다. 

또한 #define은 함수 역활과 비슷하게 아래와 같이 쓰일 수 있다. 

#define SUM(x) ((x) = (x) + (x))

동작원리는 함수와 같다. 말 그대로 main소스에서 SUM을 호출하면 옆에 있는 더하기 코드가 치환되는 것이다.

 

#define으로 정의할 수 있는 것은 숫자만이 아니다.

#define MYNAME "Young Hee"

printf(MYNAME);

라고 한다면 이는 전처리기에 의해 

printf("Young Hee");와 같이 전개되는 것이다.


출처 : http://www.sosori.com/2009/09/전처리문의-종류include-define-ifdef.html

'언어 > C' 카테고리의 다른 글

getc() 함수를 사용했을 때의 오류  (0) 2016.09.28
함수 포인터 컴파일 오류  (0) 2016.09.26
signed와 unsigned  (0) 2016.05.02
typedef  (0) 2016.05.02
static 변수  (0) 2016.03.21
Posted by 知彼知己百戰不殆
,

signed와 unsigned

언어/C 2016. 5. 2. 13:31

signed unsigned는 컴퓨터 프로그램에서 수를 표기하는 자료형의 특성이다.


signed

C/C++ 프로그램 언어에서 정수형 변수 중 부호를 갖는 변수를 선언 한다. 정수형 중 음수는 2의 보수 체계를 사용하므로 이 키워드에 의해 부호를 사용할 수 있도록 변수 선언할 수 있다. 그러나 정수형의 변수에서 unsigned가 없으면 음수를 사용할 수 있는 부호를 갖는 정수형이 된다. 


unsigned

unsigned C/C++ 언어에서 사용되는 지정자로 정수형과 같이 사용되어 부호 비트를 제거해 저장 가능한 양수 범위를 두배로 늘이는 역할을 한다. char int의 signed 정수형 변수에서 MSB가 부호 비트이다. 1이면 음수이고 0이면 양수이다. 그러나 unsigned을 사용하면 음수를 사용하지 않겠다는 의미 이므로 부호 비트가 필요 없다. 따라서 이진수와 같은 십진수가 된다.


unsigned char

8비트 정수형 변수 선언 char와 결합하여 선언하면 부호 비트가 필요 없으므로 0~255 범위를 갖는다.

10진수    2진수

255        1111 1111

254        1111 1110

253        1111 1101


출처 : 위키백과

'언어 > C' 카테고리의 다른 글

함수 포인터 컴파일 오류  (0) 2016.09.26
전처리문  (0) 2016.05.02
typedef  (0) 2016.05.02
static 변수  (0) 2016.03.21
메모리 관리와 메모리의 동적 할당  (0) 2016.03.20
Posted by 知彼知己百戰不殆
,

typedef

언어/C 2016. 5. 2. 07:49

1. 원래의 이름을 못 쓰게 하지 않는다. 즉, 원래의 이름 + 가명을 사용할 수 있는 것

2. 같은 자료형에 대해서 여러가지 새로운 이름을 만들 수 있다.


사용하는 이유??

1. 여러 시스템 환경에서 사용할 수 있는 프로그램을 만들기 위해서(ex. 16bit 컴퓨터에서 뿐만이 아니라 32bit 컴퓨터에서도 사용될 수 있게 만들고 싶을 때) - typedef으로 선언된 문장 하나만 변경하면 typedef alias로 선언된 모든 문장들에 영향을 끼침

2. 자체적으로 문서화된 프로그램을 작성하는데 도움을 주기 위해서. 어느 누구라도 코드를 읽기 쉽게 하기 위해

'언어 > C' 카테고리의 다른 글

전처리문  (0) 2016.05.02
signed와 unsigned  (0) 2016.05.02
static 변수  (0) 2016.03.21
메모리 관리와 메모리의 동적 할당  (0) 2016.03.20
파일 입출력 -3  (0) 2016.03.18
Posted by 知彼知己百戰不殆
,

static 변수

언어/C 2016. 3. 21. 14:16

'언어 > C' 카테고리의 다른 글

signed와 unsigned  (0) 2016.05.02
typedef  (0) 2016.05.02
메모리 관리와 메모리의 동적 할당  (0) 2016.03.20
파일 입출력 -3  (0) 2016.03.18
파일 입출력 -2  (0) 2016.03.13
Posted by 知彼知己百戰不殆
,

힙 영역 : 사용자가 원하는 시점에 변수를 할당/소멸 하도록 지원. '프로그래머가 관리하는 메모리 공간'이라고도 하는데, malloc 함수 호출로 할당된 메모리 공간은 프로그래머가 직접 free 함수 호출을 통해 해제하지 않으면 계속 남아있다.

지역변수와 같이 함수가 호출될 때마다 매번 할당이 이뤄지지만, 할당이 되면 전역변수와 마찬가지로 함수를 빠져나가도 소멸되지 않는 성격의 변수가 필요. 힙에 할당된 메모리 공간은 포인터 변수를 이용해서 접근해야 한다. 주소 값을 반환하기 때문.


힙 영역의 메모리 공간 할당과 해제 : malloc, free 함수

1
2
3
4
#include <stdlib.h>
 
void * malloc (size_t size);
void free (void * ptr);


malloc 함수는 성공 시 할당된 메모리의 주소 값 반환, 실패 시 NULL 반환


malloc 함수의 반환형은 void * 형이므로 반환값에 아무런 가공도 하지 않으면 할당된 메모리 공간에 접근 불가능.

malloc 함수는 원하는 만큼 메모리 공간 할당하고, 그 메모리의 주소 값 반환. 사용하려면 포인터 형의 변환을 통해 결정해야 함.

형변환 연산자를 사용하여 int * ptr1 = (int *)malloc(sizeof(int)); 이런 식으로 형변환을 해줘야 할당된 메모리 공간에 접근 가능.


힙 영역의 메모리 공간 할당 함수 : calloc 함수 (메모리 공간 해제시 free)

1
2
3
#include <stdlib.h>
 
void * calloc (size_t elt_count, size_t elt_size);


성공 시 할당된 메모리의 주소값, 실패 시 NULL 반환

elt_count 인자 : 할당할 블록의 개수 정보

elt_size 인자 : 블록 하나당 바이트 크기의 정보

malloc 함수와 차이점 : malloc는 할당된 메모리 공간을 별도의 값으로 초기화하지 않음(할당된 메모리 공간이 쓰레기 값으로 채워짐), calloc는 할당된 메모리 공간의 모든 비트를 0으로 초기화 시킴.


힙에 할당된 메모리 공간 확장 시 호출하는 realloc 함수

할당된 메모리 공간은 크기를 확장할 수 없지만, 그 영역이 heap이라면 가능하다.

1
2
3
#include <stdio.h>
 
void * realloc (void * ptr, size_t size);


성공 시 새로 할당된 메모리의 주소 값, 실패 시 NULL 반환

ptr : 확장하고자 하는 힙 메모리의 시작 주소 값

size : 확장하고자 하는 메모리의 전체 크기

1. malloc 함수의 반환 값(주소값)과 realloc 함수의 반환 값이 같은 경우

=> 기존에 할당된 메모리 공간의 뒤를 이어서 확장할 영역이 넉넉한 경우

2. malloc 함수의 반환 값과 realloc 함수의 반환 값이 다른 경우

=> 넉넉하지 않은 경우 힙의 다른 위치에 새로 할당(이전 배열에 저장된 값 복사)

'언어 > C' 카테고리의 다른 글

typedef  (0) 2016.05.02
static 변수  (0) 2016.03.21
파일 입출력 -3  (0) 2016.03.18
파일 입출력 -2  (0) 2016.03.13
파일 입출력 -1  (0) 2016.03.10
Posted by 知彼知己百戰不殆
,