관계 대수

기본 연산자

단항 연산자(unary operator)

  • 셀렉트
  • 프로젝트
  • 리네임

이항 연산자(binary operator)

  • 합집합
  • 차집합
  • 카티션 프로덕트

<참고. 그리스 소문자>

이름 소문자
시그마 σ (대문자는 Σ)
파이 π
ρ
세타 θ

단항 연산자

셀렉트

릴레이션에서 조건을 만족하는 레코드를 선택하는 것으로 시그마 기호로 표시한다.

σ조건(R)

σ번지=231(회원)

프로젝트 연산자

한 릴레이션의 여러 속성 중 특정 속성만 선택하는 것으로 파이 기호로 표시한다.

수학적인 관점에서 릴레이션은 집합이므로 프로젝트된 릴레이션에서 중복되는 레코드는 제거된다.

πA1,A2,...,An(R)

π주소,전화번호,소속(회원)

리네임 연산자

관계 대수식에서 결과로 생성된 릴레이션은 이름이 없어, 참조할 수 있는 이름을 부여해야 한다.

리네임 연산으로 그리스 소문자 로(ρ)를 사용한다.

<R을 x로 이름을 부여>

ρx(R)

ρcs번지=231(회원))

<R을 x로 이름을 부여하고 n개의 속성 이름까지 부여>

ρx(A1,A2,...,An)(R)

이항 연산자

집합 연산자

집합론을 이론적 배경으로 하는 릴레이션은 동일한 스키마를 만족하는 레코드의 집합이라고 할 수 있기 때문에 릴레이션에서 합집합, 교집합, 차집합 연산자를 동일하게 적용할 수 있다.

릴레이션은 호환 가능한 릴레이션간에 사용할 수 있으므로 집합 연산자를 사용하기 위해서는 아래 두 조건을 만족해야 한다.

집합 연산자를 사용하기 위한 두 릴레이션을 R과 S라 할때

  1. R과 S는 가지고 있는 속성의 수가 같아야 한다.
  2. 모든 i에 대해 릴레이션 R의 i번째 속성의 모데인과 릴레이션 S의 i번째 속성의 도메인이 서로 같아야 한다.
합집합 연산자

두 개의 릴레이션을 입력으로 받는 이항 연산자로, 두 릴레이션이 포함된 모든 레코드를 갖는 릴레이션을 결과값으로 가지며, 합집합 연산자 '∪'를 나타낸다.

π회원명(σ주소='서울'∧'성별='남')(회원) ∪ π회원명(σ주소='경기'∧'성별='남')(회원)

논리 접속자: ∨, ∧, ¬, ⊃, ≡

차집합 연산자

차집합 연산자는 한 릴레이션에는 포함되고 다른 릴레이션에는 포함되지 않는 레코드를 가지는 릴레이션을 결과값으로 가지며, '-'로 나타낸다.

π회원명(σ집주소='서울'∧'성별='남')(회원) - π회원명(σ근무지='서울'∧'성별='남')(회원)

교집합 연산자

입력 받은 두 릴레이션에 동시에 포함되는 레코드들의 집합을 결과값으로 가지며, 교집합 연산자 '∩'로 나타낸다.

π회원명(σ집주소='서울'∧'성별='남')(회원) ∩ π회원명(σ근무지='서울'∧'성별='남')(회원)

기본 연산자의 조합

R∩S=R-(R-S)

벤다이어그램으로 생각해 보면 쉽게 이해할 수 있다.

카티션 프로덕트 연산자

앞서 언급된 단항 연산자나 서로 양립 가능한 서로 다른 두 개의 릴레이션과 다르게

서로 다른 릴레이션 간의 관계성을 이용하는 연산자로 'x'로 표시된다.

카티션 프로덕트 연산자는 두 릴레이션의 레코드 간에 모든 조합을 취하는 연산이다.

RxS={(rs) | r∈R∧s∈S}

R릴레이션의 레코드가 4개이고 S릴레이션의 레코드가 4개이면 44=16개가 된다.*

조인 연산

카티션 프로덕트 연산과 다르게 두 릴레이션에서 서로 관련된 레코드만 결합하여 결과 집합에 포함시킨다.

σ회원.주소=사원.주소(회원x사원)

세타 조인

조인 연산 가운데 하나로 관계 연산자 'θ'로 정의되는 조인조건을 가진다.

A라는 속성을 갖는 릴레이션 R과 B라는 속성을 갖는 릴레이션 S에 대한 세타 조인(⋈AθB) 정의

R⋈AθBS=σAθB(RXS)

정의에서 θ는 관계연산자 {=,<,<=,>,>=,!=} 중에 하나가 된다.

θ가 '='이면 동등 조인 또는 이쿼 조인(equi join)이라 하며, 다음과 같이 표현할 수 있다.

회원⋈회원.주소=사원.주소사원

'database' 카테고리의 다른 글

관계 대수의 기본 연산자  (0) 2019.06.02
MariaDB(MySQL) 외부 접근 허용|금지하기  (0) 2019.05.09

우분투에서 런처 만들기

우분투에서 패키지 관리자에서 설치하지 않고, 다운로드 받아 사용하려면 터미널에서 실행하거나 런처를 만들어 이클립스를 실행한다.

작업환경

  • 우분투 18.04

요구사항

  • vim 또는 텍스트 에디터
  • 이클립스 다운로드 후 압축해제
  • 이클립스 실행파일의 위치와 아이콘의 위치 확인

런처(launcher) 만들기

쉘을 실행(Ctrl+Alt+T)

$ sudo vim /usr/share/applications/eclipse.desktop

아래 내용을 참고해 작성합니다.

#!/usr/bin/env xdg-open
[Desktop Entry]
Version=2019-03 # 이클립스의 버전
Type=Application 
Terminal=false
Exec=/home/shin/Downloads/eclipse/eclipse # 이클립스 실행파일을 지정
Name=Eclipse JEE # 표시되는 이름
Comment=Eclipse # 설명
Icon=/home/shin/Downloads/eclipse/icon.xpm # 아이콘 파일을 지정

이제 Show Application에서 등록된 이클립스를 확인할 수 있다.

'ubuntu' 카테고리의 다른 글

우분투에서 런처 만들기  (0) 2019.05.31
프로세스 확인  (0) 2014.10.28
ssh 설치  (0) 2014.10.27
컴퓨터 이름 바꾸기  (0) 2014.10.26

멀티 스레드(작성중)

스레드란

그동안 작성한 프로그램을 모두 하나의 스레드로 이루어진 프로세스이다.

프로세스

멀티 태스킹

동시 실행 - 시분할 기법과 같은 다양한 기법을 이용하여 '동시 실행'하는 것과 같은 효과

스레드(Thread) - 프로세스 내의 작은 실행 단위

메인 스레드

Thread 클래스

상수

  • static int MAX_PRIORITY
  • static int MIN_PROIRITY
  • static int NORM_PRORITY

생성자

  • Thread()
  • Thread(String name)
  • Thread(Runnable target)
  • Thread(Runnable target, String name)
  • Thread(ThreadGroup group, Runnable target, String name)

메소드

  • void checkAccess()
  • static Thread currentThread()
  • String getName()
  • void setname(String name)
  • int getPriority()
  • void setPrority(int newPrority)
  • void interrup()
  • static boolean isInterupted()
  • boolean isAlive()
  • void join()
  • void join(long mills)
  • void start()
  • static void yield()
  • static void sleep(long millis)

java api 문서 참고 필요

스레드와 관련 있는 Object 클래스에 정의된 메소드

  • void wait()
  • void wait(long millis)
  • void notify()
  • void notifyAll()

스레드의 생성 방법

Thread 클래스를 이용하거나 Runnable 인터페이스를 이용하는 방법이 있는데
자바는 다중 상속을 지원하지 않으므로 다른 클래스의 상속을 받지 않는 경우 Thread 클래스를 상속 받아 스레드를 구현하고, 다른 클래스를 상속받으면서 스레드가 되게 하려면 Runnable 인터페이스를 구현하는 방법을 사용한다.

Thread 클래스를 이용하여 스레드 생성

class MyThread extends Thread {
    @Override
    public void run() { // Thread를 상속받고 run() 메소드를 구현
        System.out.println("스레드");
    }
}

public class MyThreadTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start(); // start() 메소드를 호출하면 myThread 인스턴스의 run()이 실행
    }
}

run() 메소드를 직접 호출하기 않고 start() 메소드를 통해 간접적으로 호출하는 이유는 스레드의 실행이 시스템이 관리하는 멀티 태스킹과 연관리 있기 때문이다.

Runnable 인터페이스를 이용하여 스레드 생성

class MyThread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("스레드");
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        Thread runnableTest = new Thread(new MyThread2()); // MyThread2()의 객체를 매개변수로 전달
        runnableTest.start(); // start() 메소드를 호출하면 myThread 인스턴스의 run()이 실행

    }
}

<멀티 스레드 구현>

class MyThread3 extends Thread {
    public MyThread3(String mtName) {
        super(mtName);
    }
    @Override
    public void run() {
        super.run();
        for(int i=0; i<10; i++) {
            System.out.print(this.getName()+"_"+i+",");
        }
    }
}

public class MultiThreadTest {

    public static void main(String[] args) {
        MyThread3 mt1 = new MyThread3("mtd1");
        MyThread3 mt2 = new MyThread3("myd2");
        MyThread3 mt3 = new MyThread3("mtd3");

        mt1.start();
        mt2.start();
        mt3.start();
        System.out.println("main");
    }

}

<결과>
main
mtd1_0,mtd1_1,mtd1_2,mtd1_3,mtd1_4,mtd1_5,mtd1_6,mtd1_7,mtd1_8,mtd1_9,myd2_0,myd2_1,mtd3_0,myd2_2,mtd3_1,myd2_3,myd2_4,mtd3_2,myd2_5,mtd3_3,myd2_6,myd2_7,myd2_8,myd2_9,mtd3_4,mtd3_5,mtd3_6,mtd3_7,mtd3_8,mtd3_9,

  • 스레드는 정해진 실행 순서 없이 무작위로 실행되므로 결과가 매번 다를 수 있다.
  • main이 끝에 출력되지 않는다는 점도 알 수 있다.

스레드의 제어 방법

여러 개의 스레드를 동기화하는 방법

String, StringBuffer, StringBuilder 중에 어떤 것을 사용해야 하나

String 클래스

String 변수를 초기화할 때 리터럴로 초기화된 문자열 객체는 스택 영역에 저장되고, 생성자를 통해 초기화하면 힙 영역에 저장된다.

String s1 = "java"; // 스택
String s2 = new String("java"); // 힙 영역

String 클래스의 객체는 생성된 이후 변경이 불가능한 immutable 클래스여서 문자열의 내용을 변경하는 메소드를 제공하지 않는다.

String 클래스는 기본 자료형처럼 사용할 수 있다.

String s1 = "java"; // 스택에 문자열 객체를 생성

리터럴로 다른 String형 변수를 사용하는 경우 하나의 리터럴이 공유된다.

리터럴을 사용하는 경우 리터럴을 사용하는 것이 효율적이다.

String s1 = "java";
String s2 = "java"; // s1과 동일한 문자열 객체를 가르킨다. => s1과 같은 메모리 주소!
String s3 = new String("java"); // 다른 메모리 주소를 가르킨다.

String 생성자

다음 링크에서 Constructors(생성자) 항목을 확인합니다.
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

문자열 데이터의 비교는 compareTo(), equals() 메소드를 사용한다.

String s1 = "java";
String s2 = "java";
String s3 = new String("java");
System.out.println(s1.compareTo(s3)); // 0(다르면 0이 아닌 정수값을 반환)
System.out.println(s2==s2); // 같은 메모리 주소를 가르키고 있어 true를 반환
System.out.println(s3.equals(s1)); // true(다르면 false를 반환)
System.out.println(s3.==s1)); // 다른 메모리 주소를 가르키고 있어 false를 반환

어떤 자료형이든 문자열로 변환하기 위해서는 valueOf()를 사용한다.

valueOf() 메소드는 static 메소드이기 때문에 객체를 생성하기 않고 바로 사용이 가능하다.

System.out.println(String.valueOf(123));
int[] arr = new int[5];
System.out.println(String.valueOf(arr));

StringBuffer 클래스

String 클래스와 StringBuffer클래스 비교

Sting 클래스 StringBuffer 클래스
immutable(변경 불가) mutable(문자열 객체의 내용을 변경할 수 있다.)
  • StringBuffer는 내부적으로 버퍼(Buffer)를 가지고 있어 문자열 데이터를 이곳에 저장한다.

String 문자열 객체를 수정하려면 일반적으로 StringBuffer 클래스로 변환하여 수정 후 다시 String 문자열로 전환하는 방법을 사용한다.

생성자

StringBuffer sb1 = new StringBuffer();
StringBuffer sb2 = new StringBuffer(5); // 길이 5인 버퍼를 갖는 객체를 생성
StringBuffer sb3 = new StringBuffer("java"); // test를 저장할 수 있는 버퍼를 같는 객체를 생성

메소드

StringBuffer sb = new StringBuffer();
sb.append("test"); // test문자열을 추가
System.out.println(sb.capacity()); // 버퍼 크기를 반환
System.out.println(sb.length()); // 버퍼에 저장된 문자열의 길이

append() 메소드는 boolean, double, float, int, long, String, StringBuffer형으로 오버로딩되어 정의되어 있다. (자바 API문서에서 찾아 봅시다.)

그외 메소드를 공식문서를 참고.

String, StringBuffer, StringBuilder 클래스의 비교

String, StringBuffer, StringBuilder 클래스들은 모두 java.lang 패키지에 포함되어 있어 import하지 않고 바로 사용이 가능하다.

처리속도 비교

String 클래스의 문제점

아래 <비교에 사용된 코드>에서 'String 클래스'를 먼저 살펴보겠습니다.
java는 String 자료형에 + 연산이 있을 때마다 새로운 String 객체를 만들어 냅니다.
비교를 위한 코드에서 for문에 1000번 반복되는 동안
한 번 실행할 때마다 기존의 문자열 객체는 그대로 두고 'java'가 추가된 새로운 문자열을 생성합니다.
이때 기본 문자열이 남아 있게 되고 글자 하나가 3byte라고 하면 사용되지 않는 문자열 12바이트가 메모리에 남아 있게 됩니다.
이를 1000번 반복하고 계속 누적해서 사용하지 않는 메모리가 쌓이게 되면 12byte+24byte+...998번의 크기가 되어 프로그램의 실행 속도가 점점 느려진다.

문자열을 빈번하게 변경하는 경우에는 String 클래스를 사용하지 않는다.

처리속도 비교 결과

** 처리속도 측정 방법**

  • System 클래스가 제공하는 nanoTime() 메소드를 사용
  • for문을 시작하기 전에 start에 시간을 저장하고 작업이 종료되면 end에 시간을 저장해 end시간과 start시간의 차를 측정하여 비교
  • nanoTime() 메소드는 현재 시간이 기준점부터 몇 초가 경과했는지 나타내 주는 값을 반환(단위 10-e9)

실행결과
String 클래스의 처리시간: 6.3172밀리세컨
StringBuffer 클래스의 처리시간: 0.3547밀리세컨
StringBuilder 클래스의 처리시간: 0.1514밀리세컨
실행 환경에 따라 차이가 있을 수 있지만 속도 순위는 같습니다.

결론

처리 시간은 String <<<<<<<<< StringBuffer < StringBuilder의 순이면
메모리에 대해서도 String 클래스는 기존 문자열을 그대로 두고 처리되는 반면 StringBuffer와 StringBuilder는 기존 공간에 필요한 부분만 할당받아 사용하기 때문에 메모리 낭비가 발생하지 않는다.

따라서, 바뀌지 않는 문자열은 String 클래스를 사용하고, 변경이 자주 발생하는 문자열을 다룰 때에는 StringBuffer 클래스를 사용하는 것이 더 효과적이다. Thread 환경에서와 같이 동시성 제어를 고려하지 않는 경우에는 StringBuilder 클래스를 사용하는 것이 더 효과적이다.

참고. StringBuffer는 Thread 환경을 고려한 메소드가 고려되었고, StringBuilder는 Thread 환경이 전혀 고려되지 않도록 메소드가 구현되어 속도의 차이가 발생한다.

<비교에 사용된 코드>

public class StringTest {

    public static void main(String[] args) {
        long start, end;
        final String text = "java";

        // String 클래스의 처리속도
        String str = new String();
        start = System.nanoTime();
        for(int i=0; i<1000; i++) str = str + text;
        end = System.nanoTime();
        System.out.println("String 클래스의 처리시간: "+(end-start)/100000.0+"밀리세컨");

        // StringBuffer 클래스의 처리속도
        StringBuffer sb = new StringBuffer();
        start = System.nanoTime();
        for(int i=0; i<1000; i++) sb = sb.append(text);
        end = System.nanoTime();
        System.out.println("StringBuffer 클래스의 처리시간: "+(end-start)/100000.0+"밀리세컨");

        // StringBuffer 클래스의 처리속도
        StringBuilder sbd = new StringBuilder();
        start = System.nanoTime();
        for(int i=0; i<1000; i++) sbd = sbd.append(text);
        end = System.nanoTime();
        System.out.println("StringBuilder 클래스의 처리시간: "+(end-start)/100000.0+"밀리세컨");
    }

}

예외처리

예외처리(Exception)

자바 프로그램이 실행중에 오류를 만났을때 이를 처리하는 것
예외란 자바 프로그램이 실행 도중 실행을 중단할 정도의 오류는 아니지만 비정상적으로 동작하는 것을 말한다.
자바 프로그램은 예외가 발생했을때 처리하지 않으면 예외에 대한 정보를 화면에 출력하고 실행을 종료한다.

<클래스 계층구조>

Error 클래스 Exception 클래스
시스템 구조상의 문제로 발생하는 심각한 오류 프로그램의 알고리즘이나 실행 절차상의 문제로 발생하는 경미한 오류

Exception 클래스는 Throwable 클래스가 제공하는 toString(), printStackTrace() 메소드를 상속받는다.
toString() 예외 객체를 String 형으로 변환
printStackTrace() 예외가 발생한 위치를 상세하게 화면에 출력

예외의 종류에 따른 구분

checked Exception과 unchecked Exception이 있다.

checked Exception(1)

소스코드가 예외처리를 반드시 포함해야 하는 예외로 컴파일러가 예외처리 구분을 포함하는지 확인(checked)하고 없으면 컴파일 에러가 발생한다.
Runtime Exception의 서브 클래스로 분류되는 예외를 제외한 모든 예외가 여기에 해당한다.
예를 들면 입출력과 관련된 IOException 예외가 있다.

unchecked Exception(1)

매우 자주 발생하는 예외들로 숫자를 0으로 나누거나 범위를 벗어나는 배열의 첨자를 참조하고 null 객체의 메소드를 호출하는 경우 등이 있다.
컴파일러가 예외처리 구문을 확인하지 않으며(unchecked) Runtime Exception의 서브 클래스로 분류되는 예외가 해당된다.

예외처리 방법

예외처리 구문

구문

try {
    //예외가 발생할 수 있는 코드
} catch(발생하는 예외 선언) {
    //예외처리 구문
}

checked Exception(2)

예외처리 구문의 작성시 Java API 문서에 메소드를 설명하는 부분에 명시되어 있는 메소드가 발생시킬 수 있는 예외를 참고한다.

<예 FileWriter의 IOException>

FileWriter
public FileWriter(File file)
           throws IOException
Constructs a FileWriter object given a File object.
Parameters:
file - a File object to write to.
Throws:

IOException - if the file exists but is a directory rather than a regular file,
does not exist but cannot be created, or cannot be opened for any other reason

<클래스 계층>

java.lang.Object
    java.lang.Throwable
        java.lang.Exception
            java.io.IOException

<예 FileOutputStream의 예외처리>

import java.io.FileOutputStream;
import java.io.IOException;

public class ExceptionTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            FileOutputStream output = new FileOutputStream("c:/out.txt");
            output.close();
        } catch (IOException e) {
            System.out.println(e.toString());
            e.printStackTrace();
        }
    }
}

예외가 한 개 이상인 경우 모든 예외는 Exception의 하위 클래스 이므로 Exception으로 처리도 가능하다.

unchecked Exception(2)

컴파일 오류가 발생하지 않는다. 실행 도중 비정상적으로 종료된다.
<예>

public class UnchkExceptionTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = new int[5];
        a[6] = 10;
    }
}

Java API 문서를 참고해 작성해 본다.

finally 블록

try-catch와 함께 사용되며 예외발생과 무관하게 항상 실행된다. 생략할 수 있다.
<예>


import java.io.FileOutputStream;
import java.io.IOException;

class FileOut {
    public void saveFile() {
        try {
            FileOutputStream output = new FileOutputStream("c:/out.txt");
            output.close();
        } catch (IOException e) {
            System.out.println(e.toString());
            e.printStackTrace();
        }
    }
}

public class ExceptionTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FileOut fo = new FileOut();
        fo.saveFile();
    }
}

try-catch-finally 문에서 continue, break, return 등과 같은 분기문을 사용하는 것은 피하는 것이 좋다.
만약, try 블록이 분기문에 의해 종료되어야 한다면 finally블록을 실행한 후 분기문이 실행된다.

예외의 전파

일반적으로 예외는 예외가 발생한 곳에서 처리하지만 경우에 따라 다른 곳으로 전파시킬 수도 있다.

구문

throws <예외 이름>

위 예제를 발생한 곳으로 전파해 보겠습니다.
<예 예외의 전파>

import java.io.FileOutputStream;
import java.io.IOException;

class FileOut {
    public void saveFile() throws IOException {
        FileOutputStream output = new FileOutputStream("c:/out.txt");
        output.close();
    }
}

public class ExceptionTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            FileOut fo = new FileOut();
            fo.saveFile();
        } catch (IOException e) {
            System.out.println(e.toString());
            e.printStackTrace();
        }
    }
}

사용자 정의 예외

사용자 정의 예외는 일반적으로 Exception의 서브 클래스로 정의하며, 슈퍼 클래스의 생성자를 호출하는 것이 일반적이다.
예외를 발생시킬때 'throw <예외 객체>' 구문을 사용하고, 예외를 전파하기 위해 throws <예외 이름>를 사용한다.

<예 사용자 예외>

class MyCalcEx extends Exception {
    private static final long serialVersionUID = 1L;
    public MyCalcEx() {
        super();
    }
    public String toString() {
        return "예외가 발했습니다.";
    }
}

class Calc {
    public int addNum(int x) throws MyCalcEx {
        if(x <= 0)
            throw new MyCalcEx();
        return x*x;
    }
}

public class UserException {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Calc mc = new Calc();
        try {
            System.out.println(mc.addNum(0));
        } catch(MyCalcEx e) {
            System.out.println(e);
        }
    }
}
C

C언어에서 기억 클래스의 종류

C언어에서 사용되는 기억 클래스는 자동변수(auto), 정적변수(static), 외부변수(extern), 레지스터 변수(register)가 있습니다.

자동변수

예약어: auto(생략가능하며 보통 생략)
함수가 실행되는 동안에만 기억공간 중 임시기억 장소인 stack에 존재한다.
scope는 변수가 선언된 함수 또는 블록 안으로 한정된다.
지역변수가 이에 해당한다.
초기화하지 않으면 쓰레기 값을 가질 수 있어 사용시 초기화하여 사용하는 것이 좋다.

정적변수

예약어: static
변수의 기억 영역이 프로그램이 끝날 때까지 유지된다.
static으로 선언된 변수는 함수가 종료되거나 블록을 벗어나도 지정된 값을 유지한다.
모든 전역변수가 이에 해당한다.
전역변수와 다른점은 전역은 어디에서나 접근이 가능하지만 정적변수는 선언된 지역 내에서만 접근이 가능하고, 프로그램이 실행 중에 값이 계속 유지된다.
정적변수의 선언이 이루어지면 컴파일될 때 정적인 기억 영역 확보되어 변수에 할당된다.
정적인 기억 영역은 임시기억 장소인 static이 아닌 일반 기억 영역을 말한다.
초기값 부여는 컴파일할 때 한 번 이루어지며 특별한 지정이 없으면 0으로 초기화된다.

외부변수

예약어: extern
함수의 외부에 선언되어 전역변수와 같다.
초기값은 0이고 프로그램이 종료될 때까지 유지된다.
전역변수, 정적변수, 외부변수의 다른 점은 외부변수는 다른 파일에서 외부변수로 선언된 변수의 값을 참조할 수 있다는 것이다.
기억 영역의 할당은 정적변수와 같다.

레지스터 변수

예약어: register
CPU 내의 레지스터에 자료를 저장한다.
기억장치보다 레지스터의 자료입출력이 빠르기 때문에 실행 속도를 조금이나마 늘리기 위해 사용한다.
특별한 경우가 아니면 전역변수를 권장
자동변수와 동일한 속성을 가지고 있으며, 일반적으로 정수형(문자형 포함) 자료에 사용된다.
전역변수로는 사용될 수 없다.
기억공간에 저장되지 않기 때문에 포인터도 상ㅇ할 수 없다.

예를 들어 32bit 컴퓨터의 경우 레지스터의 크기가 32bit이므로 이 크기를 넘는 자료형을 레지스터 변수로 사용될 수 없다.

'c' 카테고리의 다른 글

C언어에서 기억 클래스의 종류  (0) 2019.05.26
vs code에서 wsl을 이용한 c/c++ 컴파일  (0) 2019.05.16

vs code에서 wsl을 이용한 c/c++ 컴파일

vs code에서 c/c++ 컴파일을 하기 위한 환경을 구성해 보겠습니다.
이 내용은 https://code.visualstudio.com/docs/languages/cpphttps://code.visualstudio.com/docs/cpp/config-wsl를 참고하였습니다.

사전준비

  • 윈도우10
  • visual studio code 설치(이하 vs code)
  • vs code에 c/c++ 확장 설치
  • 윈도우10에서 wsl 설치(설명에서는 ubuntu를 사용하고 있음.)

목표

vs code에서 컴파일 환경을 갖추고
c++ 코드를 작성하고 우분투에서 'Hello World!'를 출력하는 것까지 해 보겠습니다.

참고. c 프로그래밍을 하는 경우에도 컴파일 환경을 갖추려면 c++코드가 필요합니다. 컴파일 환경을 갖춘 후에 c 프로그래밍을 하시면 됩니다.

c 소스코드 작성

<윈도우에서>

  1. vs code 작업폴더 열기

윈도우 cmd창에서 D:\projects\helloworld 폴더를 만듭니다.(필요에 따라 바꿔서 만드세요.)
helloworld 폴더에서 'code .'을 입력하면 vs code가 현재 폴더를 열면서 실행됩니다.
실행할때 code 뒤에 '.'을 넣어 주어야 합니다.

cd d:
mkdir projects
cd helloworld
mkdir helloworld
cd helloworld
code .
  1. hello world! 코드 작성

vs code에서 새 파일을 열고, 아래 코드를 참고해 helloworld.cpp파일을 만듭니다.
우분투 shell에서 Hello World!를 출력는 코드입니다.

helloworld.cpp

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{

    vector<string> msg {"Hello", "C++", "World", "from", "VS Code!",
    "and the C++ extension!"};

    for (const string& word : msg)
    {
        cout << word << " ";
    }
    cout << endl;
}

GNU 컴파일러와 GDB 디버거 설치

<우분투 bash 쉘에서>

  1. 우분투 업데이트

컴파일러를 설치하기 전에 패키지 목록을 최신으로 업데이트하고 업그레이드까지 진행합니다.

'''
sudo apt-get update && sudo apt-get dist-upgrade
'''

  1. 컴파일러와 디버거 설치
sudo apt-get install build-essential gdb
  1. 설치확인

아래 두 명령을 실행하여 g++와 gdb의 위치를 확인합니다.
설치가 잘 되었다면 g++: /usr/bin/g++ /mnt/c/Program Files (x86)/Dev-Cpp/MinGW64/bin/g++.exe
/usr/share/man/man1/g++.1.gz 와 같이 파일의 경로를 출력됩니다. g++ 예 였습니다.

whereis g++
whereis gdb

우분투에 컴파일 폴더 준비

<윈도우 cmd에서>
윈도우에서 vs code로 컴파일을 하면 우분투에 실행파일이 만들어지는데, 이 폴더에 생성됩니다.
폴더는 윈도우와 같이 만들어 줍니다.

mkdir projects
cd projects
mkdir helloworld

vs code 설정

<윈도우 vs code에서>

이 작업을 통해 3개의 파일이 만들어 집니다. 하나씩 만들어 나가겠습니다.

  • c_cpp_properties.json
  • tasks.json
  • launch.json

c_cpp_properties.json : 컴파일 경로설정

c_cpp_properties.json 생성 및 설정

커맨드 팔렛트를 열기 위해 Ctrl+Shift+P를 누릅니다.
"C/C++"를 입력하며 나타나는 목록중에 다음을 찾아 선택합니다.

C/C++: Edit configutations (JSON)

.vscode/c_cpp_properties.json 파일이 만들어지면서 파일 열립니다.
우분투에 설치한 g++(컴파일러)의 경로를 설정하기 위해
초기 파일의 내용을 모두 지우고 아래 내용을 복사해 붙여넣기 해 주세요.

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "compilerPath": "/usr/bin/g++",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "clang-x64",
            "browse": {
                "path": [
                    "${workspaceFolder}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        }
    ],
    "version": 4
}

tasks.json : 빌드 task 만들기

tasks.json 생성 및 설정

vs code가 우분투의 g++컴파일러를 호출해 실행파일을 만들도록 설정하는 과정입니다.

명령 팔렛트(Ctrl+Shift+P)에서 'Tasks"를 입력하면 나오는 목록중에
'Tasks: Configure default build task'를 선택합니다.
이어서 '템플릿에서 tasks.json 파일 만들기'를 선택하고 'Others'를 선택합니다.

tasks.json에서 "tasks"부분을 아래와 같이 수정합니다.

아이디는 자신의 우분투 아이디를 입력합니다.

{
    "version": "2.0.0",
    "windows": {
        "options": {
            "shell": {
                "executable": "c:\\windows\\sysnative\\bash.exe",
                "args": ["-c"]
            }
        }
    },
    "tasks": [
        {
            "label": "build c on WSL",
            "type": "shell",
            "command": "g++",
            "args": [
                "-g",
                "-o",
                "/home/<우분투 아이디>/projects/helloworld/${fileBasenameNoExtension}.out",
                "${fileBasenameNoExtension}.c"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": []
        },
        {
            "label": "build cpp on WSL",
            "type": "shell",
            "command": "g++",
            "args": [
                "-g",
                "-o",
                "/home/<우분투 아이디>/projects/helloworld/${fileBasenameNoExtension}.out",
                "${fileBasenameNoExtension}.cpp"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

빌드테스트

helloworld.out 만들기
명령 팔렛트에서 Tasks: Run Task를 실행하거나 Ctrl+Shift+B를 누르면 'build c on WSL' task를 실행할 수 있습니다.
실행해서 우분투에 실행파일(helloworld.out)이 만들어지는지 확인해 봅니다.

Run Task를 실행하면 우분투 helloworld 폴더에 helloworld.out파일이 빌드됩니다. 쉘에서 실행합니다.

./helloworld.out
Hello World!

launch.json : vs code에서 디버그하기 위한 설정

마지막으로 launch.json을 만들겠습니다. 앞서 우분투에 설치한 GDB를 이용해 보겠습니다.

launch.json 생성 및 설정

메뉴바로 이동해 '디버그 > 구성 추가'를 선택하면 나타나는 목록에서 C++ (GDB/LLDB)를 선택합니다.
.vscode에 생성된 launch.json파일의 내용을 지우고 아래 내용을 붙여넣기 해 주세요.

참고

  • 아이디에는 우분투 아이디로 바뀌줍니다.
  • path는 리터럴 경로(전체 경로)를 사용합니다.
  • sourceFileMap의 설정은 하단 내용을 참고합니다.
{
"version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/<우분투 아이디>/projects/helloword/helloworld.out",
            "args": ["-fThreading"],
            "stopAtEntry": true,
            "cwd": "/home/<우분투 아이디>/projects/helloword/",
            "environment": [],
            "externalConsole": true,
            "windows": {
                "MIMode": "gdb",
                "miDebuggerPath": "/usr/bin/gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            },
            "pipeTransport": {
                "pipeCwd": "",
                "pipeProgram": "c:\\windows\\sysnative\\bash.exe",
                "pipeArgs": ["-c"],
                "debuggerPath": "/usr/bin/gdb"
            },
            "sourceFileMap": {
                "/mnt/c": "${env:systemdrive}/",
                "/usr": "나중에 wsl 경로는 넣게 됩니다."
            }
        }
    ]
}

sourceFileMap의 설정

두 가지를 확인해야 합니다.. 하나는 소스파일 드라이브이고 다른 하나는 윈도우에 설치된 wsl 우분투의 '/usr' 경로입니다.

먼저 소스파일 드라이브입니다.
wsl에서 윈도우 시스템의 c드라이브 루트는 /mnt/c로 접근합니다. 우리는 D:\projects\helloworld에서 작업을 하기 때문에 /mnt/d가 됩니다.

/mnt/d --> D:\

적용 결과

"sourceFileMap": {
    "/mnt/d": "${env:systemdrive}/",
    "/usr": "나중에 wsl 경로는 넣게 됩니다."
}

다음으로 wsl에 있는 /usr의 윈도우에서의 경로를 알아 보겠습니다.
vs code에서 helloworld.cpp파일을 열고 10번째 줄에 있는 string에서 오른쪽 클릭을 합니다. 그럼 컨텍스트 메뉴가 나오고 'Go to Declaration'을 선택합니다.

에디터에 stringfwd.h파일이 열리게 됩니다. 여기서 경로복사를 선택합니다.

메모장에서 붙여넣기 하여 복사된 경로를 확인합니다.
C:\Users<자신의 윈도우 아이디>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\LocalState\rootfs\usr\include\c++\7\bits\stringfwd.h

우리에게 필요한 부분은 C:\부터 usr\까지 입니다.

C:\Users<자신의 윈도우 아이디>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\LocalState\rootfs\usr\

\ --> \ 바꾼 후 적용합니다.

적용 결과

"sourceFileMap": {
    "/mnt/d": "${env:systemdrive}/",
    "/usr": "C:\\Users\\<자신의 윈도우 아이디>\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\\LocalState\\rootfs\\usr\\"
}

launch.json의 설정이 완료된 상태는 아래과 같습니다.

{
"version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/<우분투 아이디>/projects/helloword/helloworld.out",
            "args": ["-fThreading"],
            "stopAtEntry": true,
            "cwd": "/home/<우분투 아이디>/projects/helloword/",
            "environment": [],
            "externalConsole": true,
            "windows": {
                "MIMode": "gdb",
                "miDebuggerPath": "/usr/bin/gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            },
            "pipeTransport": {
                "pipeCwd": "",
                "pipeProgram": "c:\\windows\\sysnative\\bash.exe",
                "pipeArgs": ["-c"],
                "debuggerPath": "/usr/bin/gdb"
            },
            "sourceFileMap": {
                "/mnt/d": "${env:systemdrive}/",
                "/usr": "C:\\Users\\<자신의 윈도우 아이디>\\AppData\\Local\\Packages\\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\\LocalState\\rootfs\\usr\\"
            }
        }
    ]
}

컴파일

helloworld.cpp를 빌드하도록 하겠습니다.
vs code에서 파일을 열고
커맨드 팔렛트에서 'Tasks: Run Build Task' --> 'build cpp on WSL' 순으로 선택하거나
Ctrl+Shift+B를 누르고 'build cpp on WSL' 순으로 선택합니다.

vs code 하단 터미널에 아래 내용이 출력이 됩니다.

> Executing task: g++ -g -o /home/<우분투 아이디>/projects/helloworld/helloworld.out helloworld.cpp <
터미널이 작업에서 다시 사용됩니다. 닫으려면 아무 키나 누르세요.

이제 우분투에서 확인해 보겠습니다.
윈도우에서 wsl 우분투를 실행하고 프로젝트 폴더로 이동합니다.
빌드된 파일을 실행할때는 './helloworld.out'을 입력하면 됩니다. ('.'로 시작합니다.)

cd ~/projects/helloworld/
./helloworld.out

아래 메세지가 출력됩니다.

Hello C++ World from VS Code! and the C++ extension!

디버깅

마지막으로 디버깅입니다.
vs code에서 파일을 열고 F5키를 누룹니다.

편집기는 main()의 첫번째 구문에서 자동으로 멈추게 됩니다.

디버깅을 준비가 완료되었습니다.

마치며

고생하셨습니다. 글이 길어지다 보니 설명이나 스샷을 충분히 넣지 못한 부분이 있습니다. 다음에 좀 더 보완하도록 하겠습니다.
감사합니다.

'c' 카테고리의 다른 글

C언어에서 기억 클래스의 종류  (0) 2019.05.26
vs code에서 wsl을 이용한 c/c++ 컴파일  (0) 2019.05.16

장고에서 소셜인증하기 - 1. 설치

개요

네이버 아이디를 통해 장고 어플리케이션에 인증을 처리합니다.
적용할 패키지는 django-allauth로 인증, 등록, 계정 관리 및 타사 (소셜) 계정 인증을 처리할 수 있습니다.

총 3회에 걸쳐 소개합니다.

  1. 파이썬 패키지 설치
  2. 네이버 오픈API 이용 신청
  3. 장고에 소셜 어플리케이션 등록

사용환경

  • Python 2.7, 3.3, 3.4, 3.5 or 3.6
  • Django (1.11+)
  • 네이버 오픈API 앱 등록 정보

파이썬 패키지 설치

장고

장고 프로젝트 또는 가상환경에서 파이썬 패키지를 설치합니다.

pip install django-allauth

settings.py

  • 중의. INSTALLED_APPS에 'django.contrib.sites'가 있어야 합니다.
# Specify the context processors as follows:
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                # Already defined Django-related contexts here

                # `allauth` needs this from django
                'django.template.context_processors.request',
            ],
        },
    },
]

AUTHENTICATION_BACKENDS = (
    ...
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',
    ...
)

INSTALLED_APPS = (
    ...
    # The following apps are required:
    'django.contrib.auth',
    'django.contrib.messages',
    'django.contrib.sites',

    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    # 네이버 외에 다른 오픈아이디 제공자를 추가하려면 [여기](https://tinyurl.com/y6tsrngg)에서 찾아 추가하면 됩니다.
    'allauth.socialaccount.providers.naver',
)

SITE_ID = 1

LOGIN_REDIRECT_URL = '/'

urls.py

urlpatterns = [
    ...
    url(r'^accounts/', include('allauth.urls')),
    ...
]

설치 후

데이터베이스 테이블을 생성합니다.

./manage.py migrate

추가 작업이 남아 있어 네이버 오픈아이디로 로그인을 할 수 없지만 장고의 기본 로그인과 로그아웃은 동작합니다.

+ Recent posts