20140411 (용어, Register Summary, volatile, 구조체 복사, 공용체)

40일차

 

 

--------------

용         어

--------------

--- JTAG

디버거 역할.

cpu, memory, register등 모니터링

 

--- Watchdog Timer

스스로 신호를 감지해 시스템에 오류가 났을 시에 시스템을 리셋.

 

--- Brown-out Detection

회로마다 가용전압이 있는데 최고전압을 넘었을 시 회로가 타버리고, 최저전압 밑으로 떨어졌을 시 어떤 장비는 켜있고, 어떤 장비는 깜빡깜빡하고, 어떤 장비는 꺼지는 등으로 오작동을 일으킬 수 있으므로 최저전압 밑으로 떨어질 시 리셋을 시키는 장비.

 

--- RC Oscillator

주파수 발진기. CPU가 동작하도록 일정 주파수를 발생시켜줌

 

- 수정에 전기를 가하면 수정마다 특정 주파수가 계속 나온다.

딱딱이 : 수정을 쇠로 때리면 전자가 나온다. 그때 불꽃 발생.

 

--- SMD

Small Mounted device

칩형으로 소형화된 장비

 

--- lead, pad

 

lead는 다리가 나와 있는 것

pad는 뒷면에 홈이 있는 것.

 

 

--- Register Summary (p.366 ~ 368)

Reg 목록

ex)

 

- 그림을 크게 보면 주소에 "$1B ($3B)" 라고 있는데

$1B 는 호환용이고, () 는 ATMega128전용이다.

 

- CPU가 8Bit 이므로 Register도 8Bit 이다.

 

 

--- ATMega Pin Configurations

실사

 

- PA0 ~ PA7 : 8개

- PB0 ~ PB7 : 8개

- PC0 ~ PC7 : 8개

- PD0 ~ PD7 : 8개

- PE0 ~ PE7 : 8개

- PF0 ~ PF7 : 8개

- PG0 ~ PG4 : 5개

 

 

- 칩 내부에 PA0 ~ PA7 구조

- PORT'X' 라고 쓴것은 각 PA, PB,... PG 까지 A, B, ..가 X에 들어간다.

정리하자면 각 P 마다 저런 구조가 7개(ABCDEFG) 있다.

 

- DDRA 는 PORTA 에 입/출력 셋팅.

1 : 출력, 0 : 입력

- PORTA 는 우선 문을 여는지 닫는지 역할쯤으로 보자.

1 : 열기, 0 : 닫기

 

 

 

--- 지금까지 뭔말인지 모르겠지만 우선 소스를 보자.


int main()
{
 *((volatile unsigned char *)0x3A) = 0x01;  //  DDRA = 0000 0001    pa01번을 출력으로
 *((volatile unsigned char *)0x3B) = 0x01;  //  PORTA = 0000 0001  pa01번을 출력함.

 while(1);
 return 0;
}

이런식으로 ATMega 프로그래밍을 하는데 위의 소스는 LED에 불을 켜는 소스다.

우선 PA0 자리를 통해서 LED에 불을 키려하는데 Register Summary를 참고하여

0x3A는

DDRA의 레지스터 주소값이라고 알았다.

DDRA를 먼저 찾은 이유는 위에서 설명했듯 PortA의 입출력을 결정하는

이 주소값에 값을 바꾸어 입출력을 바꾸는 여기서는 출력으로 바꿨다.

그래서 0x3A에 값을 바꿔주는 것이다.

또 여기서 0x01 (0000 0001)을 주는 이유는 위에 표에서 bit0번째가 가리키는 곳이

PA0에 해당하는 자리이다. (위에 ATMega Pin 그림 참고)

PortA는 문 같은 역할로 알고 있자.

 

volatile은 최적화를 안한다는 의미인데

cpu에서 최적화를 위해서 어떤 값을 불러들이려는데 캐시에 저장되어 있다면

메모리에 가지 않고 바로 캐시에서 가져와 작업을 하는 최적화를 하는데

이것을 하지 않고 느리겠지만 다시 메모리에서 가져오라는 의미이다.

임베디드에서는 속도도 중요하지만 정확해야 하기 때문에

센서등을 제어할때 꼭 이 명령어를 붙인다고 한다.

 

아래는 프로그램 실행시 칩의 결과

 

LED판에 하나가 불이 들어옴

 

 

 

 

 

-C

--------------------

구조체와 공용체

--------------------

 

--- 구조체는 복사가 가능하다

어제 함수에 인자와 리턴값을 통해 보았듯이

배열이 들어있어도 구조체는 복사가 가능하다.

아래 소스 코드를 보자.

ex)

#include <stdio.h>

typedef struct _smart
{
     int a[3];
     char b[3];
}Smart;

int main()
{
     Smart s1 = { {1, 2, 3}, "AB\0" };
     Smart s2;

     s2 = s1;

     printf("%d %d %d \n", s2.a[0], s2.a[1], s2.a[2] );
     printf("%s \n", s2.b );

     return 0;
}

출력 화면

 

배열은 복사가 불가능한데 구조체면 가능하다.

그러나 복사할 때 자원이 많이 낭비되므로 이 방법은 비추천이고

포인터를 사용하는 것을 추천한다.

 

 

--- 공용체

구조체와 다르게 메모리를 공유한다.

무슨말이냐면 아래 소스 코드를 보자.

ex)

#include <stdio.h>

typedef union _smart
{
     int a;
     short b;
     char c;
}Smart;

int main()
{
     Smart ss;

     ss.a = 0x12345678;

     printf("%X \n", ss.a);
     printf("%X \n", ss.b);
     printf("%X \n", ss.c);

     return 0;
}

출력 화면

 

a에만 값을 넣었는데 b, c에도 값이 들어간 것이 보이는가?

저런 식으로 메모리를 잡았을 경우 메모리 구조는

이런식으로 A의 공간에 B, C가 공동으로 사용한다.

이것이 공용체.

 

그럼 무슨 좋은점이 있는가?

아래의 소스를 보자.

ex)

#include <stdio.h>

typedef union _smart
{
     int a;
     short b[2];
     char c[4];
}Smart;

int main()
{
     Smart ss;

     ss.a = 0x12345678;

     printf("a : %X \n", ss.a);
     printf("b : %X %X\n", ss.b[0], ss.b[1]);
     printf("c : %X %X %X %X \n", ss.c[0], ss.c[1], ss.c[2], ss.c[3]);

     return 0;
}

출력 화면

출력 화면에서 보이듯이

4byte 짜리든, 2byte짜리든 상수를 입력 받았을 때에 상위, 하위 비트로 나눌 수 있다.

지금은 상위, 하위 비트를 나눌 일이 없지만, 만약 생겼을 경우

공용체를 사용하면 손 쉽게 상위, 하위를 나눌 수 있다.

순서가 얶갈린 것은 little endian 방식이기 때문에 거꾸로 표시 되어있다.

 

 

설정

트랙백

댓글

20140410 (프로그램 실행 구조, AvrStudio4 실행, 구조체 포인터, typedef struct)

39일차

 

 

 

---------------------

프로그램 실행 구조

---------------------

- PC와 ATMega128의 구조를 보자

 우선 PC에서 프로그램이 실행되는 순서를 보자.

소스코드가 실행파일로 바뀌어 HDD에 저장되어 있다가

실행하면 Loader에 의해 Memory로 Loading된다.

그리고 CPU가 그것을 실행한다.

 

 

H/W와 S/W의 구조는 이렇게 되어있다.

H/W 와 같은 자원(키보드, USB, CPU...)들을 제어하는 각각의 Device Driver가 있다.

운영체제에서 Device Driver를 관리한다.

예를 들어 C로 프로그램을 짜는데 키보드에 입력을 받아 그것을 화면에 출력한다는  프로그램을 만들었다면, 운영체제에서 Driver들을 통해 키보드 입력을 제어 하고 화면에 표시하는 제어를 한다. 이런식으로 흘러 간다.

앞으로 배울 ATMega128은 우리가 직접 H/W를 조작하는 구조이다.

그래서 더 적합하게 움직이지만 더 심각한 오류도 날 수있다.

 

 

- AvrStudio4

AvrStudio4 는 프로그램 작성, ATMega128에 프로그램을 지우고 심어주는 프로그램이다.

PC에서 컴파일해서 ATMega로 넣어주는데 이런것을 Cross compile이라 부르고, AvrStudio4를 Cross Compiler라고 부른다.

아래는 프로그램을 넣는 과정.

 

 

 

 

Erase Device는 안에 있는 내용을 지우기이다.

먼저 지우고 Program을 누르면 프로그램이 들어간다.

 

 

- main.c

ATMega에서 main.c 소스를 보면 윈도우와 다르다.

makefile이 같은 폴더에 있어야 하고,

return 전에 무한 루프를 항상 갈겨줘야 한다는것!?

int main()

{

    while(1);

    return 0;

}

위에 프로그램 구조에서 보았듯이 윈도우 프로그램은 프로그램이 끝나면 돌아갈 곳(?)인 OS가 있지만,

ATMega의 경우 돌아갈 곳(?)이 없기 때문에 끝내버리면 대부분 멈추지만 가끔 오작동을 일으키는 경우가 있다고 하니 무한루프를 걸어준다.

돌아갈 곳이라니 뭔가 좀 웃기구만....

 

 

 

 

 

 

 

---C

--------------------

구조체 포인터

--------------------

 

---------------------------------

--- void형 포인터로 가리킬 경우

ex)

struct smart

{
    int a;
    short b;
    float c;
    char d;
    int e;
};

int main()

{

struct smart test = {100, 50, 4.1, 10, 1};

void * vp = &test       //      구조체의 주소값만 넘겨주면 된다.


printf("a : %d \n", test.a);
printf("a : %d \n", *((int *)vp) );

vp = (char *)vp + 4;
printf("b : %d \n", *((short *)vp) );

vp = (char *)vp + 4;
printf("c : %f \n", *((float *)vp) );

vp = (char *)vp + 4;
printf("d : %d \n", *((char *)vp) );

vp = (char *)vp + 4;
printf("e : %d \n", *((int *)vp) );

printf("tset : %d \n", sizeof(test) );

return 0;

}

출력 화면

 

-------------------

- 구조체 포인터

ex) 위의 구조체와 상동

int main()
{
     struct smart test = {100, 50, 4.1, 10, 1};
     struct smart * stp = &test;

 printf("a : %d \n", stp->a);
 printf("b : %d \n", (*stp).b);
 printf("c : %f \n", test.c);
 printf("d : %d \n", stp->d);
 printf("e : %d \n", stp->e);

     return 0;
}

이런식으로 구조체 포인터를 사용한다.

stp->a   ==   (*stp).a     는 같은 뜻이다.

 

 

 

--------------------

--- typedef struct

- struct smart 변수    // 이런식으로 하기에는 좀 길다

그래서 좀 줄이기 위해 typedef를 선언.

ex)

struct smart
{
    int a;
    short b;
    float c;
    char d;
    int e;
};
typedef struct smart Smart;

int main()
{
     Smart test = {100, 50, 4.1, 10, 1};

     return 0;
}

이런식으로도 사용이 가능하고

 


typedef struct smart
{
    int a;
    short b;
    float c;
    char d;
    int e;
}Smart;

int main()
{
     Smart test = {100, 50, 4.1, 10, 1};

     return 0;
}

이런식으로 한방에 다 선언, 정의도 가능하다.

한 방에 가능하니 많은 이들이 요놈을 선호한다고 한다.

 

 

 

 

--- 구조체를 함수의 인자로, 리턴값으로도 넘길 수 있다.

ex)

typedef struct _num
{
     int a;
     int b;
}Num;

Num AddNum(Num nNum)
{
     ++nNum.a;
     ++nNum.b;

return nNum;

}

int main()
{
     Num nNum = {1, 10};

 nNum = AddNum(nNum);

 printf("%d %d \n", nNum.a, nNum.b);

     return 0;
}

출력 화면

 

이런식으로 함수의 인자, 리턴값으로도 할 수 있다.

그러나 인자든 리턴값이든 메모리에 새로 복사하게 되므로

중복값이 생기니 메모리 낭비, CPU 계산 낭비등 자원등을 낭비하는 사태가 초례된다.

 

그러므로 포인터를 사용해야한다.

ex)

typedef struct _num
{
     int a;
     int b;
}Num;

Num * AddNum(Num * nNum)
{
     ++nNum->a;
     ++nNum->b;

     return nNum;
}

int main()
{
     Num nNum = {1, 10};

     AddNum(&nNum);

     printf("%d %d \n", nNum.a, nNum.b);

     return 0;
}

출력 화면

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140409 (CPU, Microcontroller, RAM, ROM, RISC, CISC, 구조체, #pragma pack)

38일차

 

 

------------

상     식

------------

 

----------------------------

--- CPU, Microcontroller

 

- CPU는 위의 그림과 같이 core만 있고

RAM, ROM, I/O... 다른 것들은 외부에 있는 개인컴퓨터의 것과 같은 것.

 

- Microcontroller는 칩에 core, SDRAM, EEPRAM,... 등등 다른 것들이 함께 들어 있는 것.

 

 

----------------------------

- RAM, ROM 등등 메모리

 

- RAM (Ramdom Access Memory)

읽기 쓰기가 언제나 가능하다.

휘발성 ( 전기가 끊기면 내용이 다 날아감 )

 

- ROM (Read Only Memory)

읽기만 가능

비휘발성 ( 전기가 끊겨도 내용이 저장되어 있다 )

 

- EEPROM (Electrically Erasable Programmable ROM)

읽기 쓰기 가능

비휘발성

RAM보다 비싸다

 

- Flash Memory

읽기 쓰기 가능

비휘발성

RAM, ROM보다 느리다

RAM보다 가격이 비싸, EEPROM보다 싸다

 

- SRAM (Static RAM)

전기가 가해지면 안에 내용을 유지해서 정적이라고 함.

주로 캐시메모리

DRAM에 비해 비싸다

 

- DRAM (Dynamic RAM)

전기가 가해져도 일정시간이 지나면 내용이 바뀌므로

주기적으로 전기를 다시 공급해 줘야한다. Reflesh 그래서 동적이라고 함.

주로 주기억장치

SRAM에 비해 싸다

 

- SDRAM

DRAM 업그레이드 판.

 

 

 

-----------------

--- RISC, CISC

            구조, 명령어          주 사용                      비유?

RISC         단순           서버, 슈퍼컴퓨터             물 끓이고, 스프넣고, 라면 넣고...

CISC         복잡                   PC                       라면 끓여 끝.

명령세트의 종류로 CPU에 기계어 코드이다

CISC 가 먼저 세상에 나왔는데 명령어가 엄청나게 많았다.

하지만 그 중에 실제로 자주 쓰이는 것은 10%미만에 불과하다는 것을 알아내고

자주 쓰는 것을 모아서 만든 것이 RISC 방식이라고 한다

현재에는 둘 다 서로의 장점을 수용하게 되서 경계가 무너지고 있다고들 한다...

 

 

 

------------------

--- WinAVR

AVR에 넣는 프로그램짜는 컴파일러

폴더 내에 main.c와 makefile이 함께 있어야 한다.

 

- make

컴파일 명령어

- make clean

컴파일한 파일 다 지우기

- main.hex

실행 파일

 

 

 

 

C 언어

---------------

구    조    체

---------------

- 구조체 사이즈 출력

ex)

#include <stdio.h>

struct smart
{
  int a;
};

int main()
{
  printf("%d \n"sizeof(struct smart));

  return 0;
}

- struct smart  이것 자체가 자료형이다.

 

 

여기서 알 수 없는 것이 있었다....

ex)

#include <stdio.h>

struct smart
{
  int a;  //  4  4
  int b;  //  8  8
};

int main()
{
  printf("%d \n"sizeof(struct smart) );

  return 0;
}

출력 화면 

문제가 없다.

아래를 더 보자

#include <stdio.h>

struct smart
{
  int a;  //  4  4
  int b;  //  8  8
  char c;  //  9  12
};

int main()
{
  printf("%d \n"sizeof(struct smart) );

  return 0;

}

출력 화면

??? 9가 나와야 하는데 12가 나왔다.

변수 // 예상크기  결과크기

#include <stdio.h>

struct smart
{
  int a;  //  4  4
  int b;  //  8  8
  char c;  //  9  12
  char d;  //  10  12
  char e;  //  11  12
  short f;  //  13  16
  char g;  //  14  16
  int h;  //  18  20
  char i;  //  19  24
  short j;  //  21  24
  char k;  //  22  28
};

int main()
{
  printf("%d \n"sizeof(struct smart) );

  return 0;
}

왜 그러냐면 컴파일러는 4byte or 2byte로 잡는게 편하기 때문에? 컴파일 편한대로? 메모리를 잡기 때문에 저런 현상이 나타난다고 한다.

 

아래 그림을 통해 메모리 구조를 보자. 

①번은 위에서 선언한 변수 순서 그대로 했을 경우 메모리가 잡히고 빈칸은 버리는 공간이 되어버렸다. 그래서 6byte 낭비.

②번은 변수 선언을 메모리가 잡히는 구조를 생각해서 A, B, F, J, C, D, E, G, H, I, K 순으로 선언 했을 경우 2번과 같이 메모리가 잡힌다. 2byte낭비.

③번은 메모리 위에 #pragma pack(1) 이라는 것이 있는데, 구조체 선언 위에 선언할 경우 컴파일러가 메모리를 잡을 때 1byte단위씩 잡게된다. 딱 맞다.

④번은 구조체 선언 위에 #pragma pack(1), 구조체 선언 밑에 #pragma pack(4) 를 선언한 경우이다. 딱 맞다.

 

장단점 비교

①번이 제일 쓰레기 코드다. 대신 프로그래머가 편하다.

②번은 ①번에 비해 메모리를 4byte를 확보. 프로그래머가 신경을 좀 써야된다.

③번은 ①번에 비해 메모리를 6byte나 확보했지만, 속도가 느리다. 편하다.

④번은 ①번에 비해 메모리 6byte 확보, 속도도 확보 가장 좋은 코드. 프로그래머가 신경 좀 써야된다.

 

 

- #pragma pack( )

위에서 한 번 언급 했듯이 컴파일시 메모리 단위를 바꾼다.

ex)

#include <stdio.h>
#pragma pack(1)

struct smart
{
 int a;  //  4  4
 int b;  //  8  8
 char c;  //  9  12
 char d;  //  10  12
 char e;  //  11  12
 short f;  //  13  16
 char g;  //  14  16
 int h;  //  18  20
 char i;  //  19  24
 short j;  //  21  24
 char k;  //  22  28
};

#pragma pack(4)

struct smart1
{
 int a; 
 int b; 
 char c;  
 char d; 
 char e; 
 short f; 
 char g; 
 int h;
 char i; 
 short j; 
 char k;  //  28
};

int main()
{
 printf("smart : %d \n", sizeof(struct smart) );
 printf("smart1: %d \n", sizeof(struct smart1) );

 return 0;
}

출력 화면 

 

 

 

- 메모리에 진짜로 위와 같이 저장되는지 변수들의 주소값 확인

1번의 경우로 확인.

ex)

#include <stdio.h>

struct smart
{
int a; // 4 4
int b; // 8 8
char c; // 9 12
char d; // 10 12
char e; // 11 12
short f; // 13 16
char g; // 14 16
int h; // 18 20
char i; // 19 24
short j; // 21 24
char k; // 22 28
};

int main()
{
 struct smart ass;

 printf("int a\t: 0x%08X \n", &ass.a);
 printf("int b\t: 0x%08X \n", &ass.b);
 printf("char c\t: 0x%08X \n", &ass.c);
 printf("char d\t: 0x%08X \n", &ass.d);
 printf("char e\t: 0x%08X \n", &ass.e);
 printf("short f\t: 0x%08X \n", &ass.f);
 printf("char g\t: 0x%08X \n", &ass.g);
 printf("int h\t: 0x%08X \n", &ass.h);
 printf("char i\t: 0x%08X \n", &ass.i);
 printf("short j\t: 0x%08X \n", &ass.j);
 printf("char k\t: 0x%08X \n", &ass.k);

 return 0;
}

출력 화면

 

 

메모리 구조와 비교 

 

- e 다음에 f 가 한칸 37비우고 38부터 시작하는 것을 볼 수 있다.

j 도 i 다음에 41부터 시작이 아니라 42부터 시작하는 것을 볼 수 있다.

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140408 (회로도 최적화, 4bit 덧셈, 구조체)

37일차

 

 

----------------

회로도 최적화

----------------

- 어제 했던 내용을 이어서

어제는 sum을 계산했고 오늘은 carry를 계산한다.

방식은 같다. 

 

실습

 

A     1

B     1

Ci    1 

인 경우

 

 

A     1

B     1

Ci    0 

인 경우

 

 

A     0

B     1

Ci    0

인 경우

 

 

A     0

B     0

Ci    0 

인 경우

 

 

--- 4bit 덧셈

4bit 덧셈을 하려면 전가산기 3개와 반가산기 1개가 필요하다

 

 

 

 

--- ATMEL

- 메모리 회사

- cpu사업도 시작했음.

- cpu 시리즈 중에 AVR, AT91.. 등등 있음

- AVR 시리즈 중에 Mega 모델 중 ATMega128을 공부할 예정.

 

--- ATMega128

- Microcontroller

- 8bit

- 128 Flash Memory

 

 

 

 

 

 

 

----------------

구  조  체

----------------

- 새로운 타입을 정의.

typedef와 다른점은 아래를 참고하자.

 

struct (타입이름)

{ (내용) };

 

- 전역에서 사용해야 하니 전역에 정의.

 

ex)

#include <stdio.h>

struct smart
{
  char  Name[7];
  char  Phone[14];
  int  Age;
};

int main()
{
  struct smart  people[3];
  int    iCnt;

  for(iCnt = 03 > iCnt; ++iCnt)
  {
    printf("이름 : ");
    scanf("%s", people[iCnt].Name);
    fflush(stdin);

    printf("전화번호 : ");
    scanf("%s", people[iCnt].Phone);
    fflush(stdin);

    printf("나이 : ");
    scanf("%d"&people[iCnt].Age);
  }

  for(iCnt = 03 > iCnt; ++iCnt)
  {
    printf("이름 : [%s], 전화번호 : [%s], 나이 : [%d] \n", people[iCnt].Name, people[iCnt].Phone, people[iCnt].Age);
  }

  return 0;
}

이런식으로 사용.

 

- 초기화

#include <stdio.h>

struct employee
{
  char  Name[7];
  char  Phone[14];
  int  Age;
};

struct employer
{
  char  Name[7];
  char  Phone[14];
  int  Age;
};

int main()
{
  struct employee  people[3= {
      {"James""010-0100-0101"10000},
      {"Ayin""010-1111-2220"9999},
      {"Watson""010-1234-5678"8000}
      };
  struct employer  CEO = {"IamCEO""000-0000-0000"40000};
  int    iCnt;

  printf("이름 : [%s], 전화번호 : [%s], 나이 : [%d] \n", CEO.Name, CEO.Phone, CEO.Age);
  
  for(iCnt = 03 > iCnt; ++iCnt)
  {
    printf("이름 : [%s], 전화번호 : [%s], 나이 : [%d] \n", people[iCnt].Name, people[iCnt].Phone, people[iCnt].Age);
  }

  return 0;
}

출력 화면

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

과제 : 문자열치환

잡다 2014. 4. 8. 14:09

 

 

처음 한 소스

#include <stdio.h>
#include <string.h>

char * Change_word(char * string, char * old_word, char *new_word);

int main()
{
  char  caOld_word[32];
  char  caNew_word[32];
  char  caString_word[50];

  fputs("Input String : ", stdout);
  fgets(caString_word, 31, stdin);
  fflush(stdin);

  fputs("Choose String to modify : ", stdout);
  fgets(caOld_word, 11, stdin);
  fflush(stdin);

  fputs("Input String to modify : ", stdout);
  fgets(caNew_word, 11, stdin);
  fflush(stdin);

  Change_word(caString_word, caOld_word, caNew_word);

  printf("Output String : %s \n", caString_word);

  getchar();

  return 0;
}

char * Change_word(char * string, char * old_word, char *new_word)
{
  int  iLength_old = 0;
  int  iLength_new = 0;
  int  iCnt_old = 0;
  int  iCnt_new = 0;
  int  iCnt1 = 0;
  int  iCnt2;
  int  iCnt_temp;
  char  caTemp[50= "";

  // ----------------------------- // 수정 문자 길이 시작
  while('\n' != old_word[iLength_old] && 0 != old_word[iLength_old] )
  {
    ++iLength_old;
  }

  while('\n' != new_word[iLength_new] && 0 != new_word[iLength_new] )
  {
    ++iLength_new;
  }

  // ---------------------------- // 수정 문자 길이 종료

  // ---------------------------- // 문자열 찾아 바꾸기 시작
  while(0 != string[iCnt1])
  {
    if(string[iCnt1] == old_word[iCnt_old]) //--- 첫 문자가 맞으면 뒷문자 확인
    {
      ++iCnt_old;
      for(iCnt2 = 1; iLength_old > iCnt2; ++iCnt2)
      {
        
        if(string[iCnt2+iCnt1] == old_word[iCnt_old])
        {
          if(iCnt_old == iLength_old-1)  //--- 끝까지 다 일치하면 치환
          {
            strcpy(caTemp, string);

            for(iCnt2 = 0; iLength_new > iCnt2; ++iCnt2)  //--- new로 바꾸기
            {
              string[iCnt2+iCnt1] = new_word[iCnt_new];
              ++iCnt_new;
            }

            iCnt_temp = iCnt1 + iLength_old;
            iCnt2 = iCnt2 + iCnt1;

            while(0 != caTemp[iCnt_temp])   //--- 나머지 문자열 넣기
            {
              string[iCnt2] = caTemp[iCnt_temp];
              ++iCnt2;
              ++iCnt_temp;
            }
            string[iCnt2] = 0;

            return string;  //--- 함수 끝
          }
          else
          {
            ++iCnt_old;
          }
        }
        else
        {
          break;
        }
      }
      iCnt_old = 0;
    }
    ++iCnt1;
  }
  // ---------------------------- // 문자열 찾아 바꾸기 종료

  return string;
}

main_before.exe

 

 

문자열 함수를 사용한 코드

#include <stdio.h>
#include <string.h>

char * Change_word(char * string, char * old_word, char *new_word);

int main()
{
  char  caOld_word[32];
  char  caNew_word[32];
  char  caString_word[50];

  fputs("Input String : ", stdout);
  fgets(caString_word, 31, stdin);
  fflush(stdin);

  fputs("Choose String to modify : ", stdout);
  fgets(caOld_word, 11, stdin);
  fflush(stdin);

  fputs("Input String to modify : ", stdout);
  fgets(caNew_word, 11, stdin);
  fflush(stdin);

  Change_word(caString_word, caOld_word, caNew_word);

  printf("Output String : %s \n", caString_word);

  getchar();

  return 0;
}

char * Change_word(char * string, char * old_word, char *new_word)
{
  int  iCnt;
  int  iCnt2;
  int  iCntOld = 0;
  int  iLengthNew = strlen(new_word);
  int  iLengthOld = strlen(old_word);
  char  temp[50];

  if('\n' == new_word[iLengthNew-1])
  {
    --iLengthNew;
  }

  if('\n' == old_word[iLengthOld-1])
  {
    --iLengthOld;
  }

  for(iCnt = 00 != string[iCnt]; ++iCnt)
  {
    if(string[iCnt] == old_word[iCntOld])  // 첫번째 문자 일치?
    {
      iCnt2 = 1;  // 두번째 부터 시작
      iCntOld = 1;  //       ``

      while(iCnt2 < iLengthOld)  // 나머지 문자 일치
      {
        if(string[iCnt2+iCnt] == old_word[iCntOld])
        {
          if(iCnt2 == iLengthOld-1)  // 마지막 문자인가?
          {
            strcpy(temp, &string[iCnt+iCnt2+1]);
            strcpy(&string[iCnt], new_word);
            strcpy(&string[iCnt+iLengthNew], temp);

            return string;
          }
          ++iCnt2;
          ++iCntOld;
        }
        else
        {
          iCntOld = 0;
          break;
        }
      }
    }
  }

  return string;
}

main.exe

 

'잡다' 카테고리의 다른 글

간단한 포토샵  (0) 2014.07.21
Raw socket  (0) 2014.06.28
Mac Address, 제조회사  (0) 2014.06.27
[vi명령어] 자동정렬 / 단어찾기 / 도스저장  (0) 2014.06.25
GNU Compiler __attribute__  (0) 2014.06.19

설정

트랙백

댓글

20140407 (반가산기 XOR없이, 회로도 최적화 공식, typedef, strlen, strcpy, strcat)

36일차

 

------------------

논리 회로

------------------

--- 반가산기 (Half Adder)

XOR 게이트가 없을 경우 

 실제)

 

 

 

 

 

--- 회로도 최적화 공식

 

 

 

 

 

----------

c 언어

----------

 

--- typedef

새로운 데이터 타입 정의

ex)

typedef unsigned int ui;

ui uiNum;

 

uiNum은 unsigned int 형으로 정의 된다.

전역영역에서 선언해 주는게 좋다.

 

 

--- strlen

#include <string.h>

size_t strlen(const char * s);

문자열 길이 리턴.

 

--- strcpy, strncpy

#include <string.h>

char * strcpy(char * dest, const char * src);

char * strncpy(char * dest, const char * src, size_t n);

dest에 src 의 내용을 (n만큼) 복사한다.

 

--- strcat, strncat

#include <string.h>

char * strcat(char * dest, const char * src);

char * strncat(char * dest, const char * src, size_t n);

dest뒤에 src를 (n만큼) 문자를 잇는다

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140404 (Adder, NOT, NAND, puts, fputs, gets, fgets, fflush)

35일차

 

 

--------------------

반  가  산  기

--------------------

----------------

--- NOT Gate

A    Y

1     0

0     1

 

--- NAND

NOT + AND

 

 

 

L L 에 연결해 본 것.

 

 

--- 가산기 ( Half Adder )

1비트 덧셈.

 

 

 

 

 A  B  S  C

 0   0  0   0

 

 A  B  S  C

 1   0  1   0

 0   1  1   0

 

 A  B  S  C

 1   1  0   1

 

 

 

 

----------------------

문  자  열  입  출  력

----------------------

 

--- puts, fputs

- int puts(const char * s)

- int fputs(const char * s, FILE * stream)

성공시 음수가 아닌 값, 실패시 EOF반환

끝에 자동으로 엔터를 친다.

 

--- gets, fgets

- char * gets(char * s)

- char * fgets(char * s, int n, FILE * stream)

성공시 *s 의 주소값 반환, 실패시 or 파일 마지막 도달시 NULL

엔터입력 포함.

fgets함수에서 int n 의 값은 받고 싶은 글자 + 1만큼

변수를 선언해야 한다.

 

!! 주의 !!

gets() 함수는 입력을 받으며 메모리를 침범할 수 있기때문에

사용을 자제해야한다.

gets 뿐만 아니라 scanf, read, strcpy, memcpy, ...등등 전부 위험한 함수다.

그래서 fgets 를 사용해야 한다!!!

 

--- fflush

버퍼를 비우는 함수

int fflush(FILE * stream)

fflush(stdin)  입력 버퍼 비움

fflush(stdout)  출력 버퍼 비움

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140403 (TTL, AND gate, putchar, fputc, getchar, fgetc)

34일차

 

 

--------------------

디  지  털  회  로

--------------------

--- 트랜지스터

- NPN : 소량의 입력 전류와 양의 전압을 Base에 인가하면 (Vb > Ve) Collector에서

Emitter로 다량의 전류가 흐를 수 있게 된다.

- PNP : 소량의 출력 전류와 음의 전압을 Base에 인가하면 (Vb < Ve) Emitter에서

Collector로 매우 다량의 전류가 흐를 수 있게 된다.

 

트랜지스터끼리 조합하여 논리회로를 구성함.

 

 

 

--- TTL (Transistor Transistor Logic)

주로 5V 사용.

논리회로 종류로 트랜지스터 트랜지스터 구조를 말한다.

74XX 시리즈로 유명해졌다.

 

- 실제 생김새

빨강색 글씨로 1,7,8,14의 의미는

옆에 가닥가닥 각각 번호이다.

14 13 12 11 10  9  8

1   2   3   4  5  6  7

빨강색으로 줄 친 부분이 이 칩의 모델명이다.

 

 데이터 시트 (AND Gate)

A, B로 입력

Y로 출력

 

 

--- 실습

- AND Gate

 

오른쪽 밑 부분 노란줄 두 개가 파란라인에 꽂혀있다.

A  B  Y

0   0  0     ( G : 0   ,   +  :  1   ,    1이 나오면 LED에 불이 들어옴)

 

A  B  Y

1  0   0 

 

A  B  Y

0   1  0 

 

A  B  Y

1  1   1 

 

 

 

 

 

----------------

C 언어

----------------

-------------------

--- putchar, fputc

- int putchar(int c)

인자에 정수를 받아 한 문자만 아스키코드로 출력한다.

- int fputc(int c, FILE * stream)

인자에 정수를 받아 stream으로 한 문자만 아스키코드로 출력한다.

- 두 함수 리턴값은 출력된 문자(정수값)이고 에러시 EOF(-1)를 리턴.

 

--- getchar, fgetc

- int getchar(void)

한 문자만 입력 받는다.

- int fgetc(FILE * stream)

한 문자만 stream으로 부터 입력 받는다.

- 두 함수 리턴값은 입력된 문자(정수값)이고 에러시, 파일 끝에 도달시 EOF(-1)를 리턴.

 

ex) 예제

#include <stdio.h>

int MyPutchar(int);
int Mygetchar();

int main()
{
  int  iNum;

  iNum = MyPutchar('A');
  printf("\n%d \n", iNum);

  iNum = fputc('A', stderr);
  printf("\n%d \n", iNum);

  fprintf(stderr, "EOF : %d\n", EOF);

  iNum = Mygetchar();
  fflush(stdin);
  printf("%c \n", iNum);

  iNum = getchar();
  fflush(stdin);
  printf("%c \n", iNum);

  iNum = fgetc(stdin);
  printf("%c \n", iNum);

  return 0;
}

int MyPutchar(int iNum)
{
  return fputc(iNum, stdout);
}

int Mygetchar()
{
  return fgetc(stdin);
}

위의 예제를 보면

putchar, getchar는 제법 편리하고 꼬름하다는 것을 볼 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140402 (main 인자전달, stream)

32일차

 

 

---------------------------

main 함 수 로   인 자 전 달

---------------------------

 

- int main( int iNum, char * Cmd[] )

main함수 인자에 위의 인자 처럼 넣어주면

iNum에는 받은 명령어 갯수,

Cmd에는 그 명령어들이 각각 저장되어 있다.

 

ex) gcc -o main main.c

iNum 에는 4,

Cmd[0] : gcc

Cmd[1] : -o

Cmd[2] : main

Cmd[3] : main.c

이렇게 저장됨.

 

인자의 이름은 프로그래머 재량이지만 보통

int main(int argc, char * argv[])

로 많이 쓴다.    argc ( ARGument Count )  argv ( ARGument Vector )

 

 

 

-------------------------

이중 포인터와 2차원 배열

-------------------------

- 이전에 한 번 했었는데 헷갈려서 다시 한 번 언급한다.

void test ( int ** ptr )

{ A }

int main()

{

    int arr[5][3];

    test( arr );

....

위의 소스처럼 썼었는데 warning!

이유는

char ** 와 char [][] 참조수준이 다름.

서로 데이터 타입이 달라서 그랬다.

2차배열은 이중포인터와 같은 것인지 착각했었다.

그래서 고치면

void test( int (* ptr)[3] ) { A }      or      void test( int ptr[][3] ) { A }

둘 다 동일한 선언이고 '배열 포인터'이다.

- int * whoA [4]    // 포인터 배열

- int (* whoA)[4]   // 배열을 가리키는 포인터

 

 

 

------------------

Stream 흐름

------------------

- ' >' Redirection. 출력 방향을 바꾼다.

- 표준입력 (키보드) : stdin, 0

- 표준출력 (모니터) : stdout, 1

- 표준에러 (모니터) : stderr, 2

ms-dos, linux에서는 0, 1, 2로 스트림으로 쓴다.

ex)

dir > a.txt              dir 내용을 a.txt에 넣음

dir 1> a.txt            dir 내용을 a.txt에 넣음

dir 2> a.txt            dir 에러 내용을 a.txt에 넣음

 

 

- ' >> ' 이것도 redirection인데 ' > ' 와 다른 점은

> : 새로 쓰기

>> : 추가로 쓰기

 

 

- fprintf( Stream, format, ...);

printf 함수와 다르게 stream을 정해서 출력할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글

20140401 (함수 포인터, void 포인터)

32일차

 

 

------------------------

함    수    포    인    터

------------------------

- 함수의 주소값을 저장하는 포인터.

먼저 이 포인터를 선언하기 위해서는 Data Type을 알아야한다.

Data Type은 Prototype(함수원형)에서 이름 부분만 (*)로 바꾸면 된다.

ex)

int main()                                main함수의 Data Type은

{ 명령어들 }                                   int (*)()  이다

void test()                               test함수의 Data Type은

{ 명령어들 }                                  void (*)()  이다

int printf(const char *, ... )        printf함수의 Data Type은

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

 

 

- 함수 포인터 선언 및 사용

#include <stdio.h>

void test()
{
  int (*fp)(const char *, ...) = printf;

  (*fp)("hello \n");  //  C++에서는 괄호를 넣지않으면 오류라고 한다.

  fp("hello \n");  //  C에서는 위와 밑에 둘 다 가능.

  
  return ;
}

int main()
{
  void (*fp)();
  
  fp = test;

  fp();

  return 0;
}

위와 같은 방법으로 사용한다.

 

 

 

 

-------------------------

void  형    포  인  터

-------------------------

- Data Type이 void * 형이다.

타입을 안가리고 그 주소값을 warning 없이 다 받을 수 있다.

그러나 값을 가리키는 *를 붙이면 자료형이 얼만큼 인지 모르니

사용할 수 없다.

캐스팅을 하면 사용가능.

ex)

#include <stdio.h>

int main()
{
  void *  vp;
  int  iNum = 500;
  char  cNum = 100;

  vp = &cNum;
  *((char *)vp) = 99;

  vp = &iNum;
  *((int *)vp) = 400;

  printf("%d \n", cNum);
  printf("%d \n", *((int *)vp) );
  printf("%d \n", iNum);  

  return 0;
}

위에 *((char *)vp) 식으로 char * 형이라고 캐스팅을 해서 사용.

 

 

 

아래 소스는 HexaView 코드인데

void * 가 사용되는 예를 보자.

#include <stdio.h>

void HexaView(void * vpData);

int main()
{
  int  iNum = 0x12345678;

  HexaView(&iNum);

  return 0;
}

void HexaView(void * vpData)
{  
  int iCnt;
  int iCnt2;
  
  printf("===============================================================================\n");
  printf("= ADDRESS                         HEXA                             ASCII      =\n");
  printf("=-----------------------------------------------------------------------------=\n");
  
  for(iCnt2=020>iCnt2; ++iCnt2)
  {

    //----------------------------//
    //---      Address Part Start      ---//

    printf("= %08X  "vpData);

    //---      Address Part End       ---//
    //----------------------------//
  


    //---    Hexa View Part Start    ---//

    for(iCnt=016>iCnt; ++iCnt)
    {
      if(7 == iCnt)
      {
        printf("%02X  "(*((unsigned char *)vpData)) );
      }
      else
      {
        printf("%02X "(*((unsigned char *)vpData)) );
      }
      vpData = ((unsigned char *)vpData) + 1;
    }
    //---    Hexa View Part End    ----//
    //----------------------------//



    //----------------------------//
    //---        ASCII Part Start       ---//

    vpData = ((unsigned char *)vpData) - iCnt;
    for(iCnt=016>iCnt; ++iCnt)
    {
      if(0x20 <= (*((unsigned char *)vpData)) && 0x80 > (*((unsigned char *)vpData)))
      {
        printf("%c"(*((unsigned char *)vpData)));
      }
      else
      {
        printf(".");
      }
      vpData = ((unsigned char *)vpData) + 1;
    }
    //---        ASCII Part End        ---//
    //----------------------------//
    printf(=\n");
  }  
  printf("===============================================================================\n");

  return ;
}

위에 연한 빨강색 바탕으로 강조된 곳들이

void *를 사용한 곳들이다.

main 함수에서 HexaView 함수를 호출 할 때에

void *를 사용하지 않았다면

HexaView( (unsigned char *)&iNum );

이런식으로 함수를 호출할 때마다 캐스팅을 해줘야 하기때문에

편의성의 위해서 작성할 때 좀 더 코드를 길게 적어주면 좋다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

설정

트랙백

댓글