C++ 예제
ex1)
  // cpp
#include <iostream>
using namespace std;

int main()
{
  int **pArray;
  int i, j;
  int cnt = 0;

  // int형 5*7 배열 동적 할당
  pArray = new int*[5];
  for(i = 0 ; i < 5 ; i++)
  {
    pArray[i] = new int[7];
  }
  
  // 각 배열에 차례되로 숫자 입력
  for(i = 0 ; i < 5 ; i++)
  {
    for(j = 0 ; j < 7 ; j++)
    {
      pArray[i][j] = cnt;
      ++cnt;
      cout.width(2);
      cout << pArray[i][j] << endl;
    }
  }
 
  // int형 5*7 배열 해제
  for(i = 0 ; i < 5 ; i++)
  {
    delete[] pArray[i];
  }
  delete[] pArray;


  return 0;
}
  // cpp
#include <iostream>
using namespace std;

int main()
{
  int (*p)[7];
  int i, j;
  int cnt = 0;

  // 5 * 7 int 형 배열 동적 할당
  p = (int (*)[7])new int[7 * 5];

  for(i = 0 ; i < 5 ; i++)
  {
    for(j = 0 ; j < 7 ; j++)
    {
      p[i][j] = cnt;
      ++cnt;
      cout << p[i][j] << endl;
    }
  }
  
  delete[] p;  // 동 적 할당 해제

  return 0;
}


  // c
#include <stdio.h>
#include <stdlib.h>

int main()
{
  int (*p)[7];
  int i, j;
  int cnt = 0;

  // 5 * 7 int형 배열 동적 할당
  p = (int (*)[7])malloc(5 * 7 * sizeof(int));

  for(i = 0 ; i < 5 ; i++)
  {
    for(j = 0 ; j < 7 ; j++)
    {
      p[i][j] = cnt;
      ++cnt;
      printf("p[%d][%d] = %d\n", i, j, p[i][j]);
    }
  }

  // 동적 할당 해제
  free(p);
  
  return 0;
}


ex2)
#include <iostream>
using namespace std;

int main()
{
  int *pArray;
  int num;

  cout << "동적 배열크기 입력: ";
  cin >> num;

  // 동 적 배열 할당
  pArray = new int[num];

  for(int i = 0 ; i < num ; i++)
  {
    pArray[i] = i;
    cout << "[" << i << "] = " << pArray[i] << endl;
  }

  // 동적 배열 해제
  delete[] pArray;

  return 0;
}


ex3)
#include <iostream>
using namespace std;

int main()
{
  int num;
  int min, sec;

  cout << "Input Seconds: ";
  cin >> num;

  min = num / 60;  // 분
  sec = num % 60;  // 초

  cout << min << " min " << sec << " sec" << endl;

  return 0;
}


ex4)
#include <iostream>
using namespace std;

int main()
{
  int num;
  int com;

  cout << "Input Number: ";
  cin >> num;

  com = (~num) + 1;  // 2의 보수

  cout << "2's complement(10진수): " << com << endl;
  cout << "2's complement(16진 수): " << hex << com << endl;

  return 0;
}



   LED 예제
  // port.h
#define PINA  (*(volatile unsigned int *)0x39)
#define DDRA  (*(volatile unsigned int *)0x3A)
#define PORTA  (*(volatile unsigned int *)0x3B)

#define PINB  (*(volatile unsigned int *)0x36)
#define DDRB  (*(volatile unsigned int *)0x37)
#define PORTB  (*(volatile unsigned int *)0x38)

#define PINC  (*(volatile unsigned int *)0x33)
#define DDRC  (*(volatile unsigned int *)0x34)
#define PORTC  (*(volatile unsigned int *)0x35)

#define PIND  (*(volatile unsigned int *)0x30)
#define DDRD  (*(volatile unsigned int *)0x31)
#define PORTD  (*(volatile unsigned int *)0x32)

#define PINE  (*(volatile unsigned int *)0x21)
#define DDRE  (*(volatile unsigned int *)0x22)
#define PORTE  (*(volatile unsigned int *)0x23)

#define PINF  (*(volatile unsigned int *)0x20)
#define DDRF  (*(volatile unsigned int *)0x61)
#define PORTF  (*(volatile unsigned int *)0x62)
  // delay_m.h
void delay(unsigned int ms);

void delay(unsigned int ms)
{
  unsigned int u = 0;
  unsigned int m = 0;

  while(1)
  {
    u++;
    if(u >= 1000)
    {
      m++;
      u=0;
    }
    if(m >= ms)
    {
      break;
    }
  }
}

ex1)
#include "delay_m.h"
#include "port.h"

int main(void)
{
  DDRF = 0xff;
  PORTF = 0xff;
  unsigned int flag = 1;

  while(1)
  {
    if(flag)
    {
      PORTF = 0x00;
      flag = 0;
    }
    else
    {
      PORTF = 0xff;
      flag = 1;
    }
    delay(500);
  }
}
// 주기적으로 LED가 켜졌다 꺼지는 코드

ex2)
#include "port.h"
#include "delay_m.h"

int main(void)
{
  DDRF = 0xff;
  PORTF = 0xff;
  unsigned char cnt = 0x00;

  while(1)
  {
    PORTF = ~cnt;
    delay(700);
    if(0xff == cnt)
    {
      cnt = 0x00;
      PORTF = 0xff;
    }
    cnt++;
  }
}
// 0부터 255까지 LED를 이용해서 카운트

ex3)
#include "port.h"
#include "delay_m.h"

int main(void)
{
  DDRF = 0xff;
  PORTF = 0xff;
  unsigned char num = 0x01;

  while(1)
  {
    PORTF = ~num;
    num <<= 1;
    if(num == 0x00)
    {
      num = 0x01;
    }
    delay(700);
  }
  return 0;
}
// 옆으로 한칸씩 LED ON

ex4)
#include "port.h"
#include "delay_m.h"

int main(void)
{
  DDRF = 0xff;
  PORTF = 0xff;
  unsigned char data = 0xff;
  unsigned int flag = 1;

  while(1)
  {
    PORTF = data;
    while((PINC & 0x01== 0x00)  // 1번 스위치가 눌러지면
    {
      if(flag)
      {
        if(0x00 == data)
        {
          data = 0xff;
        }
        else
        {
          data <<= 1;
        }
        flag = 0;
      }
    }
    flag = 1;
  }

  return 0;
}
// 1번 스위치를 누를 때마다 LED가 하나씩 켜진다. 8개 다 켜진 상태에서 다시 전부 OFF 된다.

   예제

1. 문자가 숫자인지 알려주는 isDigit 함수를 구현하세요. 문자 ch를 입력 받고, ch가 숫자인지 출력하세요. 맞다면 YES, 아니면 NO를 출력합니다.

#include <iostream>
using namespace std;

bool isDigit(char ch);  // 숫자 여부 판별 함수

int main()
{
  char ch;

  while(1)
  {
    cout << "문자: ";
    cin >> ch;

    if(isDigit(ch))  // 숫자이면
    {
      cout << "결과: YES" << endl;
    }
    else  // 숫자가 아니면
    {
      cout << "결과: NO" << endl;
    }
  }

  return 0;
}

bool isDigit(char ch)
{
  if(ch >= 48 && ch <= 57)  // '0' ~ '9'
  {
    return 1;
  }
  else
  {
    return 0;
  }
}


2. 정수 N을 입력하면 2 N승을 출력하는 프로그램을 작성하세요. , 비트 연산을 이용합니다.

그리고 -1을 입력할 경우 프로그램은 종료됩니다.

#include <iostream>
using namespace std;

int main()
{
  int num;
  unsigned int result = 0x01;

  while(1)
  {
    cout << "입력 : ";
    cin >> num;

    if(num == -1)  // -1을 입력하면
    {
      cout << "프로그램 종료" << endl;
      break;
    }

    result <<= num;  // num만큼 shift
    cout << "출력 : 2^" << num << = " << result << endl;
    result = 0x01;
  }

  return 0;
}


3. 다음과 같은 형태로 문자열이 출력되는 프로그램을 작성하시오.

1)
#include <iostream>
using namespace std;

int main()
{
  for(int i = 0 ; i < 5 ; i++)
  {
    for(int j = 0 ; j <= i ; j++)
    {
      cout << (char)('A' + j) << "\t";
    }
    cout << endl;
  }

  return 0;
}


2)
#include <iostream>
using namespace std;

int main()
{
  for(int i = 0 ; i < 5 ; i++)
  {
    for(int j = 0 ; j < 5 ; j++)
    {
      if(j == 4)
      {
        cout << 'a' << '\t';
      }
      else if(j == 3 && i >= 1)
      {
        cout << 'b' << '\t';
      }
      else if(j == 2 && i >= 2)
      {
        cout << 'c' << '\t';
      }
      else if(j == 1 && i >= 3)
      {
        cout << 'd' << '\t';
      }
      else if(j == 0 && i >= 4)
      {
        cout << 'e' << '\t';
      }
      else
      {
        cout << '\t';
      }
    }
    cout << endl;
  }

  return 0;
}



   인라인 함수

인라인 함수(Inline Function)는 새로운 종류의 함수가 아니고 함수의 속성이다. 인라인 함수의 기본 개념은 함수를 호출하는 대신에 함수의 내용을 그대로 옮겨 놓은 것이다. 인라인 함수를 사용하면 함수호출에 의해서 발생하는 오버헤드를 줄 일 수 있는 장점이 있다.
  // 인라인 함수 예제
#include <iostream>
using namespace std;

inline int SQUARE(int val)
{
  return val * val;
}

int main()
{
  cout << SQUARE(4<< endl;

  return 0;
}


   main함수의 인자
명령어에 인자가 있을 경우에 main() 함수는 인자를 가지게 된다. ANSI C에서 main() 함수의 원형은 다음과 같다.
int main(int argc, char *argv[])
첫 번째 인자 argc는 argument count에서 나온 말로 명령어 행에서 문자열의 개수이다. 문자열은 공백문자로 구분된다.
두 번째 인자 argv는 argument value에서 나온 말로 명령어 행의 각 문자열을 가리키는 포인터 배열이다.
   // main 함수 인자 예제
#include <stdio.h>

int main(int A, char *p[])
{
  int i;

  printf("%d\n", A);    // 명령어 인 자 개수
  
  for(i = 0 ; i < A ; i++)
  {
    printf("%d : %s\n", i, p[i]);  // 인 자들을 출력
  }

  return 0;
}


   구조체  
구조체는 의미상으로 연관된 여러 데이터를 하나의 이름으로 묶은 사용자 정의 자료형으로, 여러 개의 속성(구조체의 멤버)을 가지고 있는 개체를 정의할 수 있다. 다음은 기본적인 구조체 정의 형식이다.
struct 변수명
{
기본자료형 변수명;
기본자료형 변수명;
        ..........
};

구조체의 멤버는 도트연산자(.)를 사용하여 접근한다. 도트 연산자의 형식은 다음과 같다.
구조체변수.멤버이름
 // 구조체 예제
#include <stdio.h>

typedef struct  // typedef 을 이용하여 STUDENT 타입을 정의
{
  char name[20];
  int english;
  int math;
  float average;
} STUDENT;

int main()
{
  STUDENT st;  // 변수의 선언-메모리가 할당된다.

  // 키보드로부터 구조체 멤버의 값을 읽어들인다.
  printf("Please enter student name: ");
  gets(st.name);
  printf("Please enter english score: ");
  scanf("%d"&st.english);
  printf("Please enter math score: ");
  scanf("%d"&st.math);
  
  st.average = (float)(st.english + st.math) / 2;
  printf("student name: %s\n", st.name);
  printf("average: %6.3f\n", st.average);

  return 0;
}


 typedef
키워드 typedef은 새로운 자료형을 정의하는 데 사용된다. typedef은 전처리 문이 아닌 c문법이며, 긴 이름의 자료형을 짧게 정의하는 데 편리하게 이용된다. 또한 다른 시스템에 동일한 코드를 이식 할 때도 유용하게 사용 된다.
  // typedef 예제
#include <stdio.h>

typedef char NAME[20];  // 새로운 타입 정의
typedef int AGE;

int main()
{
  NAME student;  // 새로운 타입의 변수 선언
  AGE stAge;

  puts("Enter Name: ");
  gets(student);
  puts("Enter Age: ");
  scanf("%d"&stAge);

  printf("%s %d\n", student, stAge);
  
  return 0;
}


 구조체를 함수 인자로 전달
구조체를 함수 인자로 전달 할 때 call by value와 call by reference 둘 다 사용 할 수 있다. call by value 방법으로 전달하는 방법은 시스템에 부하가 많이 걸리므로 되도록이면 사용하지 않고 call by reference 방법을 이용하는 것이 좋다.


   함수 오버로딩
오버로딩이란 여러 함수들이 동일한 이름을 사용할 수 있는 기능을 말한다. 어떤 함수들이 이름은 똑같으면서 인자의 종류(시그니처)만 다르다면 이 함수들은 오버로드되었다고 말한다. 오버로딩을 사용함으로써 인자의 종류에 상관 없이 동일한 코드를 사용할 수 있다.
 기본적인 오버로딩 규칙
1. 컴퓨터는 인자의 타입을 확인해서 그에 가장 잘 어울리는 시그니처를 가진 함수를 호출하게 된다.
2. 반환 값만 틀린 경우는 오버로드 할 수 없다.
3. 시그니처가 다르더라도 오버로드 할 수 없는 경우
   void SameSignature(int i);
   void SameSignature(int& r);
 적당한 함수를 찾는 순서
1. 정확하게 일치하는 경우(Exact Match)
2. 승진에 의한 형변환(Promotion)
3. 표준 형변환(Standard Conversions)
4. 사용자에 의한 형변환(User-defined Conversions

   // 함수 오버로딩을 보여주는 예제
#include <iostream>
using namespace std;

void function(void)
{
  cout << "Function(void) call" << endl;
}

int function(char c)
{
  cout << "Function(char c) call" << endl;
}

void function(int a, int b)
{
  cout << "Function(int a, int b) call" << endl;
}

int main()
{
  function();  // void function(void) 함수 호출
  function('a');  // int fuction(char c) 함수 호출
  function(1213);  // void function(int a, int b) 함수 호출

  return 0;
}
 


 디폴트 인자
디폴트 인자는 우리가 따로 값을 지정해주지 않은 경우에 선택하는 인자의 값을 말한다. 디폴트 인자의 경우에는 함수를 호출 할 때 해당 인자의 값을 적어주지 않아도 된다.
  // 디폴트 인자를 보여주는 예제
#include <iostream>
using namespace std;

int boxvolume(int length, int width = 1int height = 1);

int main()
{
  cout << "[3, 3, 3]  : " << boxvolume(333<< endl;
  cout << "[5, 5, def]  : " << boxvolume(55<< endl;
  cout << "[7, def, def]  : " << boxvolume(7<< endl;

  return 0;
}

int boxvolume(int length, int width, int height)
{
  return length * width * height;
}


   동적할당
동적 메모리 할당은 말 그대로 메모리를 동적으로 할당한다는 뜻이다. 메모리의 크기를 프로그램이 실행되는 도중에 동적으로 결정하여 할당하며, 메모리를 할당하고 해제하는 시점이 자유롭다. 단, 동적 메모리 할당으로 할당한 메모리는 사용자가 직접 해제해주기 전까지는 절대로 컴퓨터에 위해서 해제되는 일이 없으므로 신경써서 해제해주지 않으면 메모리 누수가 일어난다.

 연산자 new, delete, new[], delete[]

new, delete는 변수 하나를 동적으로 할당하는 것이고 new[], delete[]는 배열을 동적으로 할당할 때 사용한다.
  // 동적 할당 예제
#include <iostream>
using namespace std;

int main()
{
  int size;

  cout << "할당하고자 하는 배열의 크기";
  cin >> size;

  int *arr = new int[size];

  for(int i = 0 ; i < size ; i++)
  {
    arr[i] = i + 10;
  }
  for(int j = 0 ; j < size ; j++)
  {
    cout << "arr[" << j << "] = " << arr[j] << endl;
  }
  delete[] arr;

  return 0;
}


 동적 메모리 할당과 관련된 기본적인 규칙
1. new, delete와 new[], delete[] 쌍을 맞춰서 사용하자.
2. NULL 포인터를 해제하는 것은 안전하다.
3. 해제한 메모리를 또 해제해서는 안 된다.
  // 할당 받은 메모리를 해제할 때..
#include <iostream>
using namespace std;

int main()
{
  // 메모리를 할당한다.
  short *p = new short[100];

  cout << "p = " << p << endl;
  delete[] p;
  p = NULL;

  cout << "p = " << p << endl;
  delete[] p;
  p = NULL;

  return 0;
}
// 할당 받은 메모리를 해제 할 때, 그 공간은 더 이상 유효하지 않으므로 그 공간을 가리키는 포인터 변수를 NULL로 초기화 함으로써 더 신뢰성 있는 코드를 작성할 수 있다.

 동적 할당 내부 동작

기본적으로 c프로그램의 메모리 구조는 다음과 같다. 동적할당을 하게 되면 Heap영역에 메모리가 할당된다.
Stack : 지역변수
Heap : 동적할당
bss : 초기화 되지 않은 전역변수 or static변수
Data : 초기화 된 전역변수 or static변수
일반적으로 각 영역에는 다음과 같은 변수들이 할당된다.

   문자열
문자열은 문자형 배열이다. 문자형 상수는 작은따옴표를 이용하여 표시하고, 문자열 상수는 큰 따옴표로 표시한다. 문자열은 컴파일러에 의해 자동적으로 맨 마지막에 NULL 문자('\0')가 들어간다.
  // 문자열 길이를 알아보는 프로그램
#include <stdio.h>
#include <string.h>

int main()
{
  int length;
  int size;

  length = strlen("string");
  size = sizeof("string");

  printf("string length : %d\n", length);
  printf("string size : %d\n", size);
  
  return 0;
}

// strlen()함수는 정확히 문자열 길이를 출력해준다. sizeof는 변수의 메모리 공간 크기를 나타낸다.

  // strlen()함수를 직접 만들어봄
#include <stdio.h>

int strlen2(const char *p);

int main()
{
  int iNum;

  iNum = strlen2("test");
  printf("iNum = %d\n", iNum);

  return 0;
}

int strlen2(const char *p)
{
  int iCnt;

  for(iCnt = 0 ; *p != 0 ; iCnt++)
  {
    ++p;  // 포인터 위치를 한 칸씩 뒤로 옮김
  }

  return iCnt;
}


  // 문자열 함수를 이용하는 프로그램
#include <stdio.h>
#include <string.h>

int main()
{
  char stringA[80= "everywhere people stare ";
  char stringB[80= "every and each day";
  char stringC[80= "";

  char ch = '\0';
  char *pch = &ch;

  printf("stringA : %s\n", stringA);
  printf("length of stringA : %d\n", strlen(stringA));

  // stringA 와 stringB의 비교
  printf("compare string: %d\n", strcmp(stringA, stringB));
  printf("compare string: %d\n", strncmp(stringA, stringB, 5));
  
  // stringC 에 stringA 복사
  strcpy(stringC, stringA);
  printf("stringC : %s\n", stringC);
  printf("stringC : %s\n\n", strncpy(stringC, stringB, 10));

  // stringA에 stingB 붙이기
  strcat(stringA, stringB);
  printf("%s\n\n", stringA);

  // 문자열에서 'y'문자 검색
  printf("stringB : %s\n", stringB);
  pch = strchr(stringB, 'y');
  if(pch == NULL)
  {
    printf("Not exist\n");
  }
  else
  {
    printf("'y' position %d from head\n", pch - stringB);
  }

  pch = strrchr(stringB, 'y');
  if(pch == NULL)
  {
    printf("Not exist\n");
  }
  else
  {
    printf("'y' position %d from tail\n", pch - stringB);
  }
  return 0;
}

const와 포인터

const라는 키워드는 포인터에 두 가지 방법으로 사용된다. 첫 번째 방법은 상수 객체를 지시하는 포인터를 만드는 것이다. 상수 객체를 지시하는 포인터를 사용하여 그 포인터가 지시하는 값을 변경할 수 없다. 두 번째 벙법은 자신을 상수로 만드는 것이다. 상수 포인터를 사용하여 그 포인터가 지시하는 장소를 변경할 수 없다.
int age = 39;
int sage = 25
const int *pt = &age;    // 첫 번째 방법
int * const pt1 = &sage;    // 두 번째 방법
*pt = 40;        // 잘못된 사용
pt = &sage;        // 사용 가능
*pt1 = 40;        // 사용가능
pt1 = &age;        // 잘못된 사용

다차원 배열

c언어에서는 1차원 배열을 확장시켜 일반화한 다차원 배열을 지원한다. 2차원 배열은 1차원 배열의 각 원소가 배열로 구성된 배열의 배열이다.
code
#include <stdio.h>

int main()
{
  int i, j;
  int array[3][4= {
    {15234556},
    {34527623},
    {43629184},
  };

  for(i = 0 ; i < 3 ; i++)
  {
    for(j = 0 ; j < 4 ; j++)
    {
      printf("%d ", array[i][j]);
    }
    printf("\n");
  }

  return 0;
}


// 다차원 배열을 보여주는 예제

code
#include <stdio.h>

int main()
{
  int a[5= {};
  int b[3][4= {};
  
  printf("&a[4] = %p\n"&a[4]);
  printf("(a + 4) = %p\n\n", (a + 4));

  printf("b = %p\n", b);
  printf("&b[0][0] = %p\n"&b[0][0]);
  printf("&b[1][0] = %p\n"&b[1][0]);
  printf("&b[2][0] = %p\n\n"&b[2][0]);

  printf("b[0] = %p\n", b[0]);
  printf("b[1] = %p\n", b[1]);
  printf("b[2] = %p\n\n", b[2]);

  printf("(b + 0) = %p\n", (b + 0));
  printf("(b + 1) = %p\n", (b + 1));
  printf("(b + 2) = %p\n\n", (b + 2));

  printf("&a + 1 = %p\n"&a + 1);
  return 0;
}


// 다차원 배열 구성 요소들의 의미를 잘 보여주는 예제

* c언어에서는 배열 자체가 인수로 전달될 수 없다. 즉 call by value방법으로 인수 전달은 가능하지 않다. 배열을 함수 인자로 넘길 때는 call by reference를 사용한다.

c++ 기본

c++언어를 이용하여 c언어를 처음 접할 때, 작성하는 "Hello, World" 프로그램에 입력 받는 코드까지 간단히 작성해 보았다
code
#include <iostream>

int main()
{
  int a;
  int b;

  std::cout << "Hello, World\n";
  std::cin >> a >> b;
  std::cout << a << "\t" << b << std::endl;

  return 0;
}


// c++에서는 iostream을 기본적으로 include 시킨다.
// 출력은 cout << 이용하고, 입력은 cin >> 이용한다.

namespace

프로그램밍 프로젝트 규모가 커짐에 따라, 변수명이라든지 함수명 등 이름 충돌의 가능성이 높아지고 있다. 이를 위해 c++표준은 이름 사용 범위를 더 잘 제어할 수 있도록 namespace이라는 기능을 제공한다.
code
#include <iostream>

namespace A    // namespace A
{
  void printTest()
  {
    std::cout << "namespace A test\n";
  }
}

namespace B    // namespace B
{
  void printTest()
  {
    std::cout << "namespace B test\n";
  }
}

using namespace B;  // B:: 사용하지 않고 함수 등을 사용가능하게 해준다

int main()
{
  A::printTest();  // A namespace에 있는 printTest()함수를 실행
  printTest();  // B namespace에 있는 printTest()함수를 실행

  return 0;
}


// namespace의 사용의 예를 보여주는 코드

bool

c++에서 지원하는 논리 자료형
code
#include
 <iostream>
using namespace std;

int main()
{
  bool b1;
  bool b2;

  b1 = true;
  b2 = false;

  cout << "b1 = " << b1 << endl;
  cout << "b2 = " << b2 << endl;

  return 0;
}


// bool 자료형은 true(1), false(0)을 저장 할 수 있다.

Reference

c++는 Reference라는 새로운 복합형 언어를 추가했다. Reference는 미리 정의된 어떤 변수의 실제 이름 대신 쓸 수 있는 대용 이름이다. Reference의 주된 용도는 함수의 인자에 사용하는 것이다. Reference를 전달인자로 사용하면, 그 함수는 복사본 대신 원본 데이터를 가지고 작업한다.
code
#include <iostream>
using namespace std;

int main()
{
  int target = 20;

  int& ref = target;    // Reference 생 성

  cout << "ref = " << ref << endl;
  cout << "target = " << target << endl;
  cout << "&ref = " << &ref << endl;
  cout << "&target = " << &target << endl;

  ref = 100;

  cout << "ref = " << ref << endl;
  cout << "target = " << target << endl;

  return 0;
}


code
#include
 <iostream>
using namespace std;

void swap(int&int&);

int main()
{
  int x = 10;
  int y = 20;
//  int& refx = x;
//  int& refy = y;
  
  cout << "x = " << x << " y = " << y << endl;
//  swap(refx, refy);
  swap(x, y);
  cout << "x = " << x << " y = " << y << endl;

  return 0;
}

void swap(int& a, int& b)  // Reference 를 이용한 함수 인자 전달
{
  int tmp;

  tmp = a;
  a = b;
  b = tmp;

  return;
}


// Reference를 이용하면 포인터를 사용하지 않고도 main 함수에 있는 두 지역 변수를 서로 swap 시킬 수 있음을 알 수 있다.
// 현재 주석 처리 된 부분으로 swap 함수를 호출해도 정상 호출 된다.

다중 포인터

int i = 100;
int *p = &i;
int **pp = &p;
int ***ppp = &pp;

변수

주소

i

100

1000

p

1000

996

pp

996

992

ppp

992

988

위 선언을 대충 그림으로 나타내면 다음과 같다. (주소는 임의로 정한 값이다)


code
#include <stdio.h>

int main()
{
  int i = 100;
  int *p = &i;
  int **pp = &p;
  int ***ppp = &pp;

  printf("i = %d\n", i);
  *p = 90;
  printf("i = %d\n", i);
  **pp = 80;
  printf("i = %d\n", i);
  ***ppp = 70;
  printf("i = %d\n", i);
  
  return 0;
}

// *p, **pp, ***PPP 모두 i임을 알 수 있다

배열

배열은 사용자가 의미상의 연관이 있는 동일한 자료형에 속한 여러 개의 자료들을 묶어 하나의 이름으로 정의한 자료형이다. 예를 들어 25명으로 구성된 한 학급의 시험 성적을 관리한다고 할 때, 50개의 독립된 변수로 나타내었을 시 코드는 굉장히 길어 질 것이다. 이런 경우 배열을 사용하면 프로그래밍을 간단히 하면서도 변수들 사이의 연관성을 컴퓨터 내부적으로도 잘 나타낼 수 있다.
    자료형 배열명[크기];        // 배열의 선언 형식
code
#include <stdio.h>

int main()
{
  int score[10];
  int i;
  int sum = 0;
  float average;

  for(i = 0 ; i < 10 ; i++)
  {
    printf("Please enter score[%d] : ", i);
    scanf("%d"&score[i]);
  }
  for(i = 0 ; i < 10 ; i++)
  {
    sum += score[i];
  }
  average = (float)sum / 10;
  printf("average score : %f\n", average);
  
  return 0;
}


// 점수 10개를 입력 받아 평균을 구하는 프로그램

배열과 포인터는 컴퓨터 내부적으로 거의 같은 방법으로 메모리에 접근한다. 그러나 이 둘 사이의 차이를 잘 구분해야 한다. 포인터는 메모리의 주소를 가지는 변수로 그 주소를 이용해서 메모리에 접근하는 것에 비해, 배열명은 그 배열에 할당된 메모리의 시작주소를 나타내는 상수이다.
code
#include <stdio.h>

int main()
{
  int BSP[25= {123, };
  int *p = BSP;

  printf("BSP size : %d \n"sizeof(BSP));
  printf("BSP : %p \n", BSP);
  printf("BSP[0] : %p \n"&BSP[0]);
  printf("BSP[1] : %p \n"&BSP[1]);
  printf("BSP+1 : %p \n", BSP + 1);
  printf("&BSP+1 : %p \n"&BSP + 1);
  printf("BSP : %p \n"&BSP);
  printf("\n");
  printf("*p = %d\n", *p);
  printf("*(p + 1) = %d\n", *(p + 1));
  printf("*(p + 2) = %d\n", *(p + 2));
  printf("\n");
  printf("p[0] = %d\n", p[0]);
  printf("p[1] = %d\n", p[1]);
  printf("p[2] = %d\n", p[2]);
  printf("\n");
  BSP[1= 10;
  printf("*(BSP + 1) : %d \n", *(BSP + 1));

  return 0;
}


// 위 코드로 배열과 포인터의 관계를 잘 알 수 있다.
// "&배열명"에 +1 연산을 하면 전체 배열 크기만큼 증가한다.
// 배열은 선언 시에만 { } 안에 값을 넣어서 초기화 할 수 있다.

FND data 전송

main.c
#include "port.h"
#include "delay_m.h"

int main(void)
{
  unsigned char fnd1 = 0x00;
  unsigned char fnd2 = 0x00;
  int sw_flag = 1;      // FND OUTPUT flag
  int click_flag = 0;
  int click_flag1 = 1;

  DDRF = 0xff;  // FND OUTPUT PIN
  PORTF = 0x00;
  DDRE = 0x00;  // SWITCH INPUT PIN
  PORTE = 0x00;
  DDRC = 0x01;  // CONTROL PIN
  PORTC = 0x00;
  DDRD = 0x00;  // DATA TRANSFER
  PORTD = 0x00;

  while(1)
  {
    // 
클릭 감지 부분
    if((PINE & 0x01== 0)  //  SWITCH PUSH
    {
      if(click_flag1)  // 
처음 실행..스위치가 떨어질 때까지 실행 되지 않음
      {
        click_flag = 1;
        click_flag1 = 0;
        sw_flag = !sw_flag; // toggle
        if(!(sw_flag))  // 
현재  전송
        {
          PORTC = 0x01;
          DDRD = 0xff;
          PORTD = fnd2 | (fnd1 - 1);
          delay(100);
          PORTC = 0x00;
        }
      }
    }
    else if((PINE & 0x01&& click_flag) // 
스위치가 떨어 졌을 
    {
      click_flag1 = 1;
    }
    
    // 
수신부
    if(PINC & 0x02)
    {
      DDRD = 0x00;
      fnd1 = 0x0& PIND;
      fnd2 = 0xf0 & PIND;
      PORTF = fnd2 | fnd1;
    }
    
    // FND 
카운트 부분
    if(sw_flag)
    {
      PORTF = fnd2 | fnd1;
      fnd1++;

      if(fnd1 >= 0x0A)
      {
        fnd1 = 0x00;
        if(fnd2 >= 0x90)
        {
          fnd2 = 0x00;
        }
        else
        {
          fnd2 += 0x10;
        }
      }
      delay(500);
    }
  }
  return 0;
}
// 2대의 DK128를 연결해서 FND 카운트 값을 서로 전송하는 코드이다. A DK128에서 먼저 FND에 99까지 카운트 시작, 카운트 도중에 버튼을 입력하면 카운트가 멈추고 현재 카운트 된 값이 B DK128로 전송된다. B DK128은 이 값을 받아 자신의 FND에 출력한다.
// 양 쪽에 같은 값이 찍힌 상태에서 스위치를 누르면 다시 카운트가 시작한다.

Call by reference

함수 인자 값으로 포인터를 사용함으로써 다른 함수에서 현재 함수의 변수들의 값들을 바꿀 수 있다.
p6-6.c
#include <stdio.h>

void swap(int *, int *);

int main()
{
  int x = 7;
  int y = 9;

  printf("A: initial value x = %d,  y = %d\n", x, y);
  printf("B: &= %p,  &= %p\n\n"&x, &y);
  swap(&x, &y);
  printf("G: end of main x = %d, y = %d\n", x, y);
  
  return 0;
}

void swap(int *px, int *py)
{
  int temp;
  printf("C: px = %p,  py = %p\n", px, py);
  printf("D: *px = %d,  *py = %d\n\n", *px, *py);

  temp = *px;    // main
함수 x변수와 y변수 값을 바꾼다.
  *px = *py;
  *py = temp;

  printf("E: px = %p,  py = %p\n", px, py);
  printf("F: *px = %d,  *py = %d\n\n", *px, *py);

}


// Call by Reference를 보여주는 예제이다. main함수의 x변수와 y변수 값을 swap함수에서 서로 바꾸고 있다. 즉 main함수의 지역변수를 swap함수에서 서로 바꾸기 위해 각 지역변수의 포인터를 인자로 넘겨주고 있다.

재귀함수

함수 자신이 스스로 자신을 호출하는 함수를 재귀함수라고 한다. 재귀함수는 코드 가독성이 떨어 질뿐만 아니라 시스템 자원 활용에 있어서도 매우 비효율적이므로 되도록이면 사용하지 않는 것이 좋다.
p6-8.c
#include <stdio.h>

void recursive_print(int);

int main()
{
  int num;

  printf("Please enter a positive integer: ");
  scanf("%d"&num);
  recursive_print(num);

  return 0;
}

void recursive_print(int n)
{
  if(n <= 0)
  {
    return;
  }
  else
  {
    printf("recursive_print: n = %d\n", n);
    recursive_print(n - 1);  // 스스로 자신을 호출
  }
}


// 숫자를 입력 받아 1씩 감소 시키면서 그때 그때 숫자들을 화면에 출력하는 프로그램이다.

함수 포인터

함수의 이름은 함수의 시작지점을 가리키는 포인터이다. 즉 함수의 시작지점을 저장할 수 있는 포인터를 함수 포인터라 한다. 함수 포인터는 리턴타입과 인자들에 대한 정보를 가지고 있어야만 한다.
에를 들어 int printf(const char *format, ...)는 printf함수의 원형이다. 이 함수의 함수 포인터 타입은 int (*)(const char *, ...)이 된다
main.c
#include <stdio.h>

void test(int A);

int main()
{
  void (*fp)(int);    // 함수포인터 선언
  fp = test;        // 함수포인터에 test대입
  fp(10);

  // test, printf, main, scanf 함수의 시작 주소를 출력
  printf("test : %p\n", test);
  printf("printf : %p\n", printf);
  printf("main : %p\n", main);
  printf("scanf : %p\n", scanf);

  ((void(*)(int))0x8048432)(100);        // test함수를 시작 주소로 출력
  ((int(*)(const char *, ...))0x80482c4)("test...\n");    // printf함수를 시작 주소로 출력

  return 0;
}

void test(int A)
{
  printf("%d\n", A);
  return;
}


// 함수 포인터를 사용한 예이다. 함수의 시작주소만 알면 그 주소를 각 함수의 포인터 타입에 맞게 캐스팅 연산 후 호출 할 수 있다.

FND count 99 with DK128

main.c
#include "port.h"
#include "delay_m.h"

int main(void)
{
  unsigned char fnd1 = 0x00;
  unsigned char fnd2 = 0x00;
  int flag = 1;
  int check = 0;

  DDRF = 0xff;  // 
포트 초기화
  PORTF = 0x00;
  DDRC = 0x01;
  PORTC = 0x00;

  while(1)
  {
    if(PINC & 0x02)  // 
출력 신호를 받았을 
    {
      flag = 1;  // 
출력 flag set
    }

    if(flag)
    {
      PORTF = fnd2 | fnd1;
      fnd1++;
      
      if(fnd1 >= 0x0A)  // 
출력이 끝난 시점
      {
        fnd1 = 0x00;
        PORTC = 0x01;  // 
상대편 FND 출력 시작
        flag = 0;    // 
출력 flag off
        check = 1;    // C PORT 
초기화를 위한 check

        if(fnd2 >= 0x80)  // 10
자리 처리 
        {
          if(fnd2 == 0x80)  // 10
자리가 8 
          {
            fnd2 = 0x00;
          }
          else        // 10
자리가 9  
          {
            fnd2 = 0x10;
          }
        }
        else        // 10
자리를 2 증가
        {
          fnd2 += 0x20;
        }
      }
    }
    else        // 
출력 안할 
    {
      PORTF = 0x00;
    }
    
    delay(600);

    if(check)      // C PORT 
초기화
    {
      PORTC = 0x00;
      check = 0;
    }
  }
  return 0;
}

// DK128 두 대를 연결해서 99까지 카운트 하는 코드이다. 일단 A DK128에서 0에서 9까지 카운트하고, 그 다음 B DK128에서 10부터 19까지 카운트 하는 방식으로 99까지 카운트한다.
// C PORT에 핀 2개를 이용해서 서로 카운트 동기화를 한다.

fopen(), fclose(), fprinf(), fscanf()

main.c
#include <stdio.h>

int main()
{
  int i;

  fprintf(stdout, "Enter the number: ");
  fscanf(stdin, "%d"&i);
  fprintf(stdout, "i = %d\n", i);

  return 0;
}
// fprintf(), fscanf() 함수들을 사용법을 알아보았다. 이 함수들은 기본적으로 입출력 스트림을 지정 할 수 있다. 위 코드를 보면 fprintf는 stdout(모니터) 표준출력으로 출력하고 있고, fscanf는 stdin(키보드) 표준입력에서 입력받는다. 즉, 각각 printf, scanf와 같은 동작을 한다고 보면 된다.

main1.c
#include <stdio.h>

int main()
{
  fprintf(stdout, "one\n");
  fprintf(stderr, "two\n");
  fprintf(stdout, "three\n");

  return 0;
}
// stdout은 표준출력, stderr은 표준에러로 둘 다 모니터로 출력된다. 기본적으로 둘 다 모니터로 출력은 되지만 엄밀히 따지면 서로 다른 스트림이다.


// 리다이렉션(>)명령을 통해 이를 확인 할 수 있었다.

p5-9.c
#include <stdio.h>

int main()
{
  int score;
  char name[10];
  FILE *fpin;
  FILE *fpout;

  fpin = fopen("d0327.in""r");
  fpout = fopen("d0327.out""w");

  while(!(feof(fpin)))
  {
    fscanf(fpin, "%s %d", name, &score);
    fprintf(stdout, "%s %d\n", name, score);
    fprintf(fpout, "%s\t%d\n", name, score);
  }
  fclose(fpin);
  fclose(fpout);

  return 0;
}


// fopen(), fclose() 함수를 이용하여 직접 파일에서 데이터를 읽어오고 데이터를 써보는 코드이다. 기본적으로 파일 입출력을 위해서 FILE 구조체 포인터가 필요하며, 파일을 이 구조체에 연결시켜주는 함수가 fopen()이고 파일을 다 쓴 후 연결을 끈어주는 함수가 fclose()이다. 함수 원형들은 http://www.winapi.co.kr 사이트에 가보면 잘 알 수 있다.
// 이 프로그램은 d0327.in 파일에서 데이터를 읽어와서 모니터와 d0327.out으로 출력시키는 프로그램이다.

p5-10.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE *fp;
  char ch;
  int count;

  if((fp = fopen("d0328.dat""r")) == NULL)
  {
    printf("File open error!!\n");
    exit(1);
  }

  count = fscanf(fp, "%c"&ch);
  while(count != EOF)
  {
    putchar(ch);
    count = fscanf(fp, "%c"&ch);
  }
  fclose(fp);

  return 0;
}


// 이 프로그램은 d0328.dat에서 데이터를 문자 단위로 읽어와서 화면에 출력해주는 프로그램이다.

더블클릭

main.c
#include "port.h"

#define LED_ON(led)    PORTF &= (~(0x01 << led))
#define LED_OFF(led)  PORTF |= (0x01 << led)

int main(void)
{
  unsigned int us = 0;
  unsigned int ms = 0;
  char click_count = 0;  // 
클릭 횟수 카운트
  char start_flag = 0;  // 
더블 클릭 시간감지 플래그
  char action = 0;    // 
클릭에 대한 액션을 결정

  DDRF = 0xff;  // 
포트 최기화
  PORTF = 0xff;
  DDRC = 0x00;
  PORTC = 0x00;
  
  while(1)
  {
    if(ms >= 500)  // 
시간 카운트 종료
    {
      start_flag = 0;
      ms = 0;
      action = click_count;
      click_count = 0;
    }
    else if((PINC & 0x01== 0)  // 
버튼을 눌렀을 
    {
      if(click_count == 0 || (click_count % 2== 0)
      {
        start_flag = 1;
        click_count++;  // 
버튼을 눌렀을  카운트 
      }
    }
    else if((PINC & 0x01&& start_flag)  // 
버튼 땠을 
    {
      if((click_count % 2== 1)
      {
        click_count++;  // 
버튼을 땠을  카운트
      }
    }

    us++;
    if(us >= 1000)
    {
      if(start_flag)  // 
시간 카운트 시작
      {
        ms++;
      }
      us = 0;
    }

    // 
클릭에 대한 동작 코드
    if(action)
    {
      LED_OFF(0);
      LED_OFF(1);
      LED_OFF(2);

      switch(action) 
      {
        case 1:
        case 2:
          LED_ON(0);  // 
 클릭 했을 
          break;
        case 3:
        case 4:
          LED_ON(1);  // 
더블 클릭 했을 
          break;
        case 5:
        case 6:
          LED_ON(2);  // 
트리플 클릭 했을 
          break;
        defalut :
          break;
      }
      action = 0;
    }
  }
  
  return 0;
}

// DK128에서 스위치 1번을 한번 클릭 했을 때 첫 번째 LED를 ON시키고, 더블 클릭 했을 때 두 번째 LED를 ON, 트리플 클릭 했을 때 세 번째 LED를 ON 시키는 코드이다.
// 스위치를 눌렀을 때 카운트를 하나씩 올리고 땔 때 다시 카운트를 올린다. 즉 카운트 값이 1이나2이면 한번 클릭을 한것이다.

FND 제어

delay_m.h
void delay(unsigned int ms);

void delay(unsigned int ms)
{
  unsigned int u = 0;
  unsigned int m = 0;

  while(1)
  {
    u++;
    if(u >= 1000)
    {
      m++;
      u=0;
    }
    if(m >= ms)
    {
      break;
    }
  }
}


main.c
#include "port.h"
#include "delay_m.h"

int main(void)
{
  unsigned char fnd1 = 0x00;  // 1
자리
  unsigned char fnd2 = 0x00;  // 10
자리

  DDRF = 0xff;  // 
 초기화
  PORTF = 0x00;
  DDRC = 0x00;
  PORTC = 0x00;
  
  while(1)
  {
    if((PINC & 0x01== 0)  // 
스위치를 눌렀을 
    {
      PORTF = fnd2 | fnd1;
    }
    else          // 
스위치가 눌러지지 않았을 
    {
      PORTF = fnd2 | fnd1;
      fnd1++;
      if(fnd1 >= 0x0A)  // 1
자리가 9 되면
      {
        fnd1 = 0x00;
        if(fnd2 == 0x90)  // 10
자리가 9 되면
        {
          fnd2 = 0x00;
        }
        else
        {
          fnd2 += 0x10;
        }
      }
    }
    delay(600);
  }
  return 0;
}
// 7-segment를 1부터 99까지 카운트하는 코드이다. 스위치를 누르면 카운트를 중지한다.
// 각 자리 수를 변수 2개를 OR연산해서 구현하였다.

포인터 연산

P5-4.c
#include <stdio.h>

int main()
{
  int inum;
  int *ip;
  short *sp;
  unsigned char *c;
  int i;

  inum = 0x0F5A0B43;
  ip = &inum;
  c = (unsigned char *)ip;

  printf("inum: %x  *ip: %p \n", inum, ip);
  sp = (short *)ip;  
  printf("sp: %p  *sp: %x \n", sp, *sp);
  sp++;    // short
형이라 증감연산시 2 증가 한다
  printf("sp: %p  *sp: %x \n", sp, *sp);

  for(i = 0 ; i < 4 ; i++)  // Little Endian
 확인하는 코드
  {
    printf("addr:%p  *c: %02x \n", c, *c);
    c++;  // char
형이라 증감연산시 1 증가 한다
  }

  return 0;
}


// 포인터 연산은 덧셈과 뺄셈만 허용된다. 덧셈과 뺄셈 연산 시 가리키는 자료형의 크기만큼 변한다.
// 인텔 x86 cpu들은 Little Endian 방식을 사용한다. 이를 확인하기 위해서 char형 포인터를 이용하여 1바이트씩 출력하여 확인할 수 있었다.

Debugger

Windows Visual Studio

Debugging 이란 프로그램의 논리적 오류를 찾아내서 수정하는 일이며, 이 작업을 도와 주는 툴을 Debugger라고 한다. 즉 프로그램의 논리적 오류를 검출하는데 사용하는 프로그램이 Debugger이다. 윈도우 환경에서 우리가 설치한 Visual Studio 6에는 Debugger가 포함되어 있는데, 간단한 사용법을 알아 보았다.
1. 일단 Debugging 해볼 간단한 코드를 작성해 보았다.


2. 코드를 작성하고 F7을 눌려 Build를 한다.
3. Debugging 할 부분에 F9를 눌러 Breakpoint를 건다. 밑의 그림과 같이 빨간색 점이 생긴다.


4. F5를 눌러 Debugging을 시작한다. 그러면 프로그램이 실행되고 Breakpoint에서 실행을 멈춘다.
위 그림에서 화살표는 현재 코드를 실행할 차례라는 것을 의미한다. 왼쪽 밑에 보면 Auto라는 탭이 있는데 여기는 Debugger가 알아서 변수를 등록시켜서 그 값들을 출력해준다. 현재 iNum변수가 초기화 되지 않아 쓰레기 값을 가지고 있는 것을 알 수 있다.
5. Debug 메뉴를 보면 step over, step into라는 명령이 있다. step over(F10)는 현재 행을 실행하되 블록 안으로 들어가지 않는 명령어이고, step into(F11)는 현재 행을 실행하고 블록 안으로 들어가는 명령어 이다. 여기선 iNum값들을 확인하기 위해서 F11(step into)를 눌러 진행한다.


위 그림을 보면 for문이 처음 실행되고 iNum값이 0으로 설정된 것을 볼 수 있다. 이런 식으로 변수 값들을 직접 눈으로 확인하면서 프로그램의 오류를 검출한다. 또한 오른쪽 밑의 watch에 따로 변수를 등록할 수도 있다.

오른쪽 밑 watch에 &iNum을 등록해서 주소값과 실제 가지고 있는 값을 다 알 수 있다.

Linux Debugger GDB

Linux에도 강력한 Debugger GDB가 있다. GDB는 텍스트 기반 Debugger로 많은 명령어들이 있다

l(list)

소스 보기

b

브레이크 포인트

info breakpoints

브레이크 포인트 정보(info b)

cl

브레이크 포인트 삭제

r(run)

프로그램 수행

s(step)

프로그램을 한 행씩 실행(함수 호출 시 내부로 들어감)

n(next)

프로그램을 한 행씩 실행(함수 호출 시 내부로 들어가지 않음)

c(continue)

브레이크 포인트를 만날 때까지 실행

u

현재 루프를 빠져 나감

finsh

현재 함수를 수행하고 빠져나감

return

현재 함수를 수행하지 않고 빠져나감

si

인스트럭션 단위로 s동작 실행

ni

인스트럭션 단위로 n동작 실행

watch

변수 값이 변할 때마다 알려줌

info locals

현재 상태에서 지역 변수들을 보여줌

info variable

현재 상태에서 전역 변수들을 보여줌

p(print)

해당 변수나 함수 값을 보여준다(밑에 표 참조)

p 변수=설정값

변수 값 설정

display

변수 값을 계속 보여줌(밑에 표 참조)

info frame

현재 함수의 스택 프레임을 보여줌

x

메모리 상태 검사(x/[범위][출력 형식] [범위의 단위])

disas

어셈블리 코드 보기

call

함수를 임의대로 호출 할 수 있다

signal

프로세스에게 시그널을 보낸다

set

메모리 특정 영역에 값을 설정(set {타입}[주소] = [값])

 

p [변수명]

변수 값을 출력

p [함수명]

함수의 주소를 출력

p/[출력 형식] [변수명]

변수 값을 출력 형식으로 출력

p '[파일명]'::[변수명]

파일명에 있는 전역 변수의 값을 출력

p [함수명]::[변수명]

함수에 있는 변수 값을 출력

p [변수명]@[배열 크기]

변수의 내용을 변수 배열의 크기 형태로 출력

 

display [변수명]

변수 값을 매번 화면에 디스플레이 한다

display/[출력 형식] [변수명]

변수 값을 출력 형식으로 디스플레이 한다

undisplay [디스플레이 번호]

디스플레이 설정을 없앤다

disable display [디스플레이 번호]

디스플레이를 일시 중단한다

enable display [디스플레이 번호]

디스플레이를 다시 활성화한다

 

t

2진수로 출력

o

8진수로 출력

d

부호가 있는 10진수로 출력(int)

u

부호가 없는 10진수로 출력(unsigned int)

x

16진수로 출력

c

최소 1바이트 값을 문자형으로 출력

f

부동 소수점 값 형식으로 출력

a

가장 가까운 심볼의 오프셋을 출력

기본적인 명령어는 다음과 같다. 위와 같은 코드를 리눅스에서 GDB를 이용하여 Debugging 해보았다.
1. GDB에서 Debugging을 하기 위해서는 일단 컴파일 할 때 옵션 -g를 주어야 한다. 이 옵션은 Debugging정보를 넣고, 모든 최적화 flag를 turn off 한다.
2. "$ gdb 실행파일명" 으로 GDB를 실행한다.


3. list 명령으로 소스코드를 볼 수 있다

4. b 명령으로 7번째 줄에 Breakpoint를 건다. 그리고 r명령을 눌러 실행하면 7번째 줄에서 실행을 멈춘다.

5. display명령으로 iNum의 상태를 계속 확인 할 수 있다. s 명령으로 계속 소스코드를 실행시켜 보면서 iNum값을 확인 할 수 있다.

일단 GDB를 이용하여 간단하게 Debugging을 해보았다. 윈도우 시스템에서와 달리 for문에 아무 명령문이 없었을 때, 리눅스에서는 i 값을 바로 5로 바꿔버려서 iNum값의 변화를 알 수가 없었다. 그래서 printf("test\n"); 명령문을 넣어 iNum값을 확인 할 수 있게 하였다.

 

LED ON/OFF 일반화

main.c
#include "port.h"

#define LED_ON(led)        PORTF &= (~(0x01 << led))    // led번째LED ON
#define LED_OFF(led)        PORTF |= (0x01 << led)    // led번째LED OFF
int main(void)
{
    unsigned int us = 0;
    unsigned int ms = 0;
    unsigned char led = 0x00;

    DDRF = 0xff;
    PORTF = 0x00;

    while(1)
    {
        us++;
        if(us >= 1000)
        {
            ms++;
            us = 0;
        }

        if(ms >= 500)
        {
            if(led == 8)
            {
                led = 0;
                PORTF = 0x00;
            }

            LED_OFF(led);
//            LED_ON(led);

            led++;
            ms = 0;
        }
    }
    return 0;
}

#define LED_ON(led)    PORTF &= (~(0x01 << led))
LED를 ON시키려면 Low 신호를 주면 된다. 어떤 수든 상관없이 Low를 만들려면 0을 AND연산하면 되므로 다음과 같이 원하는 비트만큼 0x01를 <<연산한 다음에 보수를 취해서 AND연산을 하면 ON시킬 수 있다.
#define LED_OFF(led)    PORTF |= (0x01 << led)
LED를 OFF 시키려면 High 신호를 주면 된다. 어떤 수든 상관없이 High를 만들려면 1을 OR연산하면 되므로 다음과 같이 원하는 비트만큼 0x01를 <<연산한 다음 OR연산을 하면 OFF 시킬 수 있다.

소수를 구하는 프로그램

main.c
#include <stdio.h>

int main()
{
    int i, j;

    printf("2\n");
    for(i = 3 ; i <= 100 ; i += 2)
    {
        for(j = 3 ; j <= i ; j += 2)
        {
            if(i % j == 0)
            {
                break;
            }
        }
        if(j == i)
        {
            printf("%d\n", i);
        }
    }
    
    return 0;
}


// 1부터 100까지 사이에 소수를 구하는 프로그램이다.
// 일단 2의 배수들은 2를 제외하고 소수가 될 수 없으므로 일단 제외하고, 나머지 수들을 각각 3부터 시작해서 2씩 증가시킨 값들로 자기 자신과 같은 값을 만날 때까지 나눠서 그 전에 나머지가 0인 값이 있으면 소수가 아니므로 제외하고, 자기 자신까지 도달하면 소수이므로 출력 시키는 방법으로 동작한다.

 

DK128간 통신으로 LED 켜기

main.c
#include "port.h"

int main(void)
{
    unsigned char led;
    
    DDRE = 0x00;
    PORTE = 0x00;

    DDRF = 0xFF;
    PORTF = 0xFF;

    DDRC = 0x00;
    PORTC = 0x00;

    while(1)
    {
        led = PINC;
        led = 0xFF - led;

        switch(led)
        {
            case 0x01 :
                DDRF = 0x01;
                break;
            case 0x02 :
                DDRF = 0x03;
                break;
            case 0x04 :
                DDRF = 0x07;
                break;
            case 0x08 :
                DDRF = 0x0F;
                break;
            case 0x10 :
                DDRF = 0x1F;
                break;
            case 0x20 :
                DDRF = 0x3F;

                break;
            case 0x40 :
                DDRF = 0x7F;
                break;
            case 0x80 :
                DDRF = 0xFF;
                break;
            default :
                DDRF = 0x00;
        }
        if(PINE & 0x01)
        {
                DDRF = 0xFF;
        }
        else
        {
                DDRF = 0x00;
        }

    }
    return 0;
}

// DK128보드 2개를 이용해서 스위치를 누를 때마다 각각 LED ON 개수를 늘려가는 코드이다. 예전 실습 시간에 작성 했던 코드에서 조금만 수정해서 작성 할 수 있었다. 일단 한쪽에선 스위치가 눌려 졌다는 신호를 받아서 LED 8개 모두를 ON 시키고, 다른 한쪽에서는 키가 눌려 졌을 때 눌러 졌다는 신호를 다른쪽 DK128한테 보내기만 하면 구현이 가능했다.
// 이 코드는 신호를 받아서 LED 모두를 ON 시키는 코드이다.

+ Recent posts