배운것들을 정리합니다.
三昧境

Flutter/Dart Language

[플러터 Flutter] Const, Final의 차이 그리고 컴파일타임과 런타임, Static

ujo_orr 2024. 6. 29. 23:04

const와 final은 둘 다 Dart에서 변경할 수 없는 변수를 선언할 때 사용되지만
사용 용도와 동작 방식에서 차이가 있습니다.

컴파일 타임과 런타임은 프로그래밍에서 코드가 실행되는 두 가지 주요 단계입니다. 이 두 개념은 코드가 언제 검증되고, 언제 실제로 실행되는지를 정의합니다.

들어가기 앞서 중요한 개념을 짚고 넘어가야 합니다.


 

저급(저수준) 프로그래밍 언어 (Low-Level Programing Language)

 

컴퓨터가 이해하기 쉽게 작성된 프로그래밍 언어로 컴퓨터 위주의 코드입니다.
수준이 낮다가 다른 뜻이 아닌, 더 하드웨어에 근간을 두고 있다는 뜻입니다. 
실행속도가 매우 빠르지만 배우기가 어려우며 유지보수가 힘든 것이 단점입니다.

일반적으로 기계어 어셈블리어를 말합니다.

 


 

기계어 (Machine Language)

 

기계어는 컴퓨터의 CPU가 직접 이해하고 실행할 수 있는 저수준의 언어로, 0과 1로 이루어진 이진수(binary digit)로 표현됩니다.
CPU의 레지스터, 메모리 주소, 명령어 등을 직접 다루기 때문에 매우 구체적이기 때문에
주로 하드웨어 코드를 빌드한다거나 하드웨어에 밀접하게 연관되어 있습니다.

하지만 0과 1로 사람이 읽고 쓰기엔 매우 어렵기 때문에 이를 보다 이해하기 쉬운 형태로 표현한 것이 어셈블리어입니다.

 


 

어셈블리어 (Assembly Language)

 

어셈블리어는 기계어 명령어에 대해 사람이 읽기 쉬운 기호를 사용합니다.
기계어와 다른 점은 알파벳도 추가로 사용할 수 있게 되어 좀 더 사람 친화적이긴 하지만 여전히 low-level의 언어입니다.

기계어와 1:1 대응이 되기 때문에 어셈블러(assembler)라는 번역 프로그램이 기계어로 변환합니다.

 


 

컴파일러 (Compiler)

고급 프로그래밍 언어를 실행 프로그램으로 만들기 위해 저급 프로그래밍 언어로 바꾸는 데 사용되는 프로그램입니다.
여기서 고급 언어란 인간 친화적 언어(C, C++, C#, JAVA, Python, Dart 등)를 말합니다.

어셈블러와 비슷한 개념이며

  • 컴파일러 = 고급언어 ➡️ 어셈블리어 번역기
  • 어셈블러 = 어셈블리어 ➡️ 기계어 번역기

라고 생각하면 됩니다.
또한

  • 소스코드(원시코드)
    • 고급언어로 작성된 코드 파일 (컴파일 이전)
  • 목적코드
    • 기계어로 작성된 코드파일 (컴파일 이후)

컴파일과정을 거쳐 출력된 코드를 목적 코드라고 부릅니다.
소스코드(원시코드)에서 목적 코드로 옮기는 과정을 
컴파일이라고 합니다.


이 단계에서 컴파일러는 소스코드를 기계어 또는 중간 코드로 변환합니다.

결국

컴파일이란?

소스코드(Source Code) → 컴파일러에 의한 컴파일 → 목적코드(Object Code)

로 이해하시면 됩니다.

 


 

고급 언어의 실행 파일 변환까지 컴파일 과정

  1. 고급 언어 (High-level Programing Language)
    • 인간 친화적 언어(C, C++, C#, JAVA, Python, Dart 등)로 소스 코드작성.

  2. 소스 코드 (Source Code)
    • 고급 언어로 작성된 코드 파일.

  3. 컴파일러 (Compiler)
    • 소스 코드를 어셈블리어로 변환하는 번역기를 거쳐 어셈블리어로 변환.

  4. 어셈블리어 (Assembly Language)
    • 저급 언어.

  5. 어셈블러 (Assembler)
    • 어셈블리어를 목적 코드로 변환하는 번역기를 거쳐 목적 코드 생성.

  6. 목적 코드 (Object Code)
    • 기계어 명령어와 데이터가 포함된 이진수(Binary) 파일.

  7. 링커 (Linker)
    • 여러 목적 코드 파일들과 라이브러리를 결합하고 외부 심볼들을 결합하고 재배치 작업을 통해 최종 실행 파일(.exe)을 만듦.

  8. 기계어 / 실행파일 (Machine Code / ExeCutable)
    • 최종 실행 파일(.exe)은 기계어 명령어로 구성되어 있으며 운영 체제에 의해 실행될 수 있음.

 

이 모든 개념을 짚고 넘어가야 컴파일 타임을 이해하기 쉽습니다.

 


 

컴파일 타임 (Compile Time)

 

컴파일 타임은 코드가 실행되기 전에 프로그램이 컴파일러에 의해 번역되는 단계입니다.

1번부터 8번까지의 과정을 컴파일 타임 이라고 합니다.

컴파일 타임에는 다음과 같은 일이 발생합니다.

  • 구문 분석 (Syntax Checking)
    • 코드의 문법이 올바른지 검사합니다. 문법 오류가 있으면 컴파일이 실패합니다.
  • 타입 체크 (Type Checking)
    • 변수와 표현식의 타입이 올바른지 확인합니다. 타입 불일치가 있으면 컴파일 오류가 발생합니다.
  • 최적화 (Optimization)
    • 컴파일러는 코드의 성능을 향상하기 위해 최적화를 수행할 수 있습니다.
  • 코드 생성 (Code Generation)
    • 소스 코드가 기계어 또는 중간 코드로 변환됩니다.

 

즉, 소스코드파일이 실행파일로 변환되는 과정을 컴파일 타임 이라고 합니다.

 


 

런타임  (Run Time)

컴파일된 실행 프로그램이 실제로 실행되는 단계입니다.
이 단계에서 프로그램은 메모리에 로드되고, CPU에서 실행됩니다.

사용자가 프로그램을 실행시킬 때 구동되는 시간을 말합니다.

런타임에는 다음과 같은 일이 발생합니다.

  • 메모리 할당 (Memory Allocation)
    • 프로그램이 실행될 때 변수와 객체에 메모리가 할당됩니다.
  • 프로세스 제어 (Process Control)
    • 프로그램의 흐름이 제어됩니다. 조건문, 반복문 등이 실행됩니다.
  • 동적 작업 (Dynamic Operations)
    • 파일 I/O, 네트워크 통신, 사용자 입력 등 동적 작업이 수행됩니다.
  • 예외 처리 (Exception Handling)
    • 런타임 오류가 발생하면 예외 처리기가 이를 처리합니다.

 

즉, 프로그램이 실제로 실행되는 단계이며 메모리 할당, 프로세스 제어, 예외 처리 등이 수행됩니다.

정리해 보자면 컴파일타임 → 런타임 순으로 실행됩니다.

 


 

const (Constant)

사전적 의미로는 '불변, 상수'라는 뜻을 가지고 있습니다.

컴파일 타임에 변수가 상수값을 정의하는 데 사용됩니다.

틀린 예
옳은 예

특징

  • 변수를 설정할 때 한 번에 설정해줘야 합니다.
  • 변수 값을 한 번만 설정할 수 있으며, 설정 후에는 변경할 수 없습니다.
  • 컴파일 과정에서 값이 결정되므로 실행 속도가 빠릅니다.
  • 메모리 할당 방식도 최적화되어 메모리 사용량을 줄일 수 있습니다.
  • 주로 변하지 않는 값 (예: 원주율, 파일 경로)을 정의할 때 사용됩니다.

 

 


 

final

사전적 의미로는 '최종'이라는 뜻을 가지고 있습니다.

런타임에 상수값을 할당하고 변수를 한 번만 변경할 수 있으며 설정 후에는 변경할 수 없습니다.

final 값을 수정하려할때 오류가 나는 모습

특징

 

  • 변수 값을 한 번만 변경할 수 있으며, 초기화된 후에는 다른 값으로 변경할 수 없습니다.
  • 컴파일 타임이 아닌 런타임에 값이 결정되므로 const에 비해 실행 속도가 느릴 수 있습니다.
  • 주로 초기화 후 값이 변경되지 않는 변수 (예: 화면 UI 요소, 데이터 객체)를 정의할 때 사용됩니다.
  • 객체의 속성에 final을 사용할 수도 있습니다.

 

최종적으로 정리하면

  • const
    • 컴파일타임에 상수값을 설정
  • final
    • 런타임에 상수값을 설정

이라 볼 수 있습니다.

 


 

static

 

static키워드는 클래스 인스턴스를 생성하지 않아도 클래스 자체를 통해 접근할 수 있는 변수를 만들 수 있습니다.

 

[플러터 Flutter] 매개변수(Parameter), 인스턴스변수(InstanceVariable), 전역변수(GlobalVariable), 지역변수(Lo

매개변수 (Parameter) // ()소괄호 안이 비어있음. player함수는 parameter가 없음.void player() { String name = "name";}// ()소괄호 내부가 parameter.void player(String name) { print(name);}매개변수는 함수나 생성자에서 사

ujo-orr.tistory.com

인스턴스는 제 블로그를 확인해 주시면 됩니다.

class MyStatic {
  static int number = 5; // static 변수
  
  static void printNumber() { // static 메서드
    print(number);
  }
}

class MyClass {
  int number = 10; // 인스턴스 변수
  
  void printNumber() { // 인스턴스 메서드
    print(number);
  }
}

void main() {
  // Static 멤버는 클래스 이름을 통해 직접 접근할 수 있습니다.
  print(MyStatic.number); // 5 출력
  MyStatic.printNumber(); // 5 출력
  
  // 인스턴스 멤버는 클래스 인스턴스를 통해 접근해야 합니다.
  MyClass myClass = MyClass();
  print(myClass.number); // 10 출력
  myClass.printNumber(); // 10 출력
}

static을 사용하지 않은 클래스 인스턴스들은 인스턴스를 생성해야 사용할 수 있지만
static은 인스턴스를 생성하지 않고도 바로 사용이 가능합니다.

MyClass의 오류
일반 클래스는 클래스의 인스턴스를 생성해줘야 사용할 수 있는모습

 

클래스 인스턴스 멤버에 static을 붙이면 그 멤버는 클래스의 인스턴스가 아니라 클래스 자체에 속합니다.
즉, 클래스의 모든 인스턴스가 공유하는 변수 또는 메서드가 됩니다.

이러한 방식처럼 다른 클래스에서도 static 멤버를 사용할 수 있습니다.

static의 장점

  • 코드 간결성 향상
    • 클래스 인스턴스를 생성하지 않고도 바로 사용 가능하여 코드를 간결하게 만들 수 있습니다.
  • 재사용성 증대
    • 여러 클래스에서 공통적으로 사용되는 데이터 및 함수를 쉽게 재사용할 수 있습니다.
  • 메모리 효율 개선
    • 클래스 변수는 모든 인스턴스에서 공유되므로 메모리 사용량을 줄일 수 있습니다.

 

static의 주의점

  • static 키워드는 클래스 내부에서만 사용 가능하며, 다른 클래스에서 직접 변수 이름을 사용하여 접근할 수는 없습니다.
    . 연산자를 통해 간접 접근이 가능합니다.
  • static 변수는 인스턴스와 독립적으로 존재하기 때문에, 인스턴스 변수와 이름이 중복될 경우 오류가 발생할 수 있습니다.
  • static 함수는 클래스 인스턴스를 참조할 수 없습니다.

 

전역 변수와 비슷할 수 있겠다 생각하실 수 있는데

Static

  • 범위
    • 클래스 내부에서만 유효하며, 클래스의 모든 인스턴스에서 공유됩니다.
  • 생명주기
    • 프로그램이 실행되는 동안 클래스가 로드될 때 생성되고 프로그램이 종료될 때 해제됩니다.
  • 캡슐화
    • 클래스의 일부로 취급되므로 접근 제어자(private)가 적용될 수 있습니다.

 

전역 변수

  • 범위
    • 프로그램의 모든 부분에서 접근 가능합니다.
  • 생명주기
    • 프로그램이 시작될 때 생성되고 프로그램이 종료될 때 해제됩니다.
  • 캡슐화
    • 캡슐화가 적용되지 않으며, 모든 코드에서 접근할 수 있기 때문에 관리와 디버깅이 어려울 수 있습니다.

 

따라서 static 변수는 클래스와 관련된 데이터를 공유할 때 유용하며, 전역 변수는 프로그램 전체에서 공유되는 데이터를 저장할 때 유용합니다.

전역 변수의 남용은 프로그램의 복잡성과 버그 발생 가능성을 높일 수 있으므로, 전역 변수 대신 static 변수를 사용하는 것이 더 나은 경우가 많습니다.