Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
iOS Developer/Objective-C

4. Objective-C 변수/상수

by Toughie 2024. 5. 6.

KAKAO-Choonsik

변수 선언

type 변수명(다수 가능);

int i, j, k;
char c, ch;
float f, salary;
double d;

 

당연히 같은 스코프 내에서 같은 이름으로 재선언은 불가능하다.

 

변수 초기화

/* 다른 파일에서 정의된 전역 변수,함수를 현재 파일에서 사용할 때 extern키워드 사용*/
extern int d = 5, f = 5;
int a = 3;
byte z = 22;
char x = 'c';

 

변수 초기화를 해주지 않으면 쓰레기값이 들어있기 때문에 꼭 초기화를 해주고 사용하자!

 

// 컴파일러에게 외부 변수의 존재를 알림(현재 파일에 정의되지 않았으니 외부에서 참조하겠다)
// C-스타일의 전방 선언 (declaration)
extern int externalInt;

int main (void) {
  //변수 선언 & 정의 definition (메모리 주소가 정해짐)
  int a, b;
  int c;
  float f;
 
  //변수 초기화(initialization)
  a = 10;
  b = 20;
  
  c = a + b;
  NSLog(@"value of c : %d \n", c);

  f = 70.0/3.0;
  NSLog(@"value of f : %f \n", f);
  return 0;
}

선언 vs 정의

선언은 컴파일러에게 타입과 이름만 알려주는 것이고,

정의는 메모리 할당까지 이루어 지는 경우를 의미한다.

대부분의 변수는 선언과 정의가 함께 이루어진다. 

 

int a; 라고 하면 아 int 자료형의 a라는 식별자를 사용하고(선언) 4byte의 메모리 공간이 필요하구나!(정의)

 

하지만 아래의 경우는 주소 바인딩이 되지 않는다.

컴파일러는 아 이런 함수와 구조체가 있구나?를 알고 컴파일을 하고 (주소 바인딩이 없으니 선언임)

이후 링크 단계에서 해당 함수의 정의부와 구조체의 정의부를 통해 적절한 메모리 주소가 바인딩 되게 된다.

// 함수 선언
void someFunction(void);
// 구조체 선언
struct x;

 

C언어 처리 단계를 간단히 살펴보자면 아래와 같다.

 

전처리

    - 전처리기에 의해 #import, #define등의 내용을 현재 소스에 포함시킨다. (컴파일러에게 전달하기 위해)

컴파일

    - 컴파일러에 의해 전처리된 소스를 기계어로 변환한다.(인라인 함수는 이때 바인딩)

링크

    - 링커에 의해 컴파일된 소스코드와 라이브러리 코드를 결합해 실행 가능한 바이너리 파일을 만든다.

    - 주로 함수 메모리 바인딩이 링크 단계에서 이루어진다.

 

 

처음에 c에서는 왜 이런식으로 하지?라는 의문이 있었는데 코드의 양이 많아지다 보니까,

전방에 변수와 함수들이 쫙 선언되어 있으면 전체적인 흐름을 파악하기에 유용하더라..


함수의 선언과 정의 예시

//함수 선언
int myFunc();

int main() {
    //함수 호출
    int i = myFunc();
}

//함수 정의
int myFunc() {
    return 777;
}

Lvalue와 Rvalue

objective c에서는 두 가지 종류의 표현식이 있다.

 

lvalue(left value)

위치를 나타내는 표현식. 할당 연산자(=)의 왼쪽에 오는 표현식을 말한다.

변수, 배열 요소, 구조체 멤버 등이 lvalue이다.

 

rvalue(right value)

'값'을 말한다. 값을 생성하거나 계산하는 표현식을 의미한다.

상수, 리터럴, 함수 리턴값 등이 rvalue이다.

 

    //lvalue   //숫자 리터럴 rvalue
int lvalue = 10;

//rvalue = rvalue라서 틀린 표현
//10 = 20;

 

c 프로젝트 하면서 lvalue 뭐시기 에러가 꽤 났었는데 별거 아니었네.. 그냥 이런거였다 ㅋㅋ


상수

말 그대로 변수와 달리 고정된 값. 리터럴이라고도 하며 숫자 리터럴, 문자열 리터럴 등으로 자주 언급된다.

 

상수 정의

#define 전처리문 사용

#import <Foundation/Foundation.h>

#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'

int main() {
   int area;
   area = LENGTH * WIDTH;
   NSLog(@"AREA : %d", area);
   NSLog(@"%c", NEWLINE);

   return 0;
}

 

상수는 주로 전부 대문자를 사용한다. 또한 할당 연산자나 세미콜론도 사용하지 않는다. 그냥 띄어쓰기로 구분한다.

 

#define은 전처리기에 의해 전처리 단계에서 처리되며 단순한 치환이 이루어져서(그냥 해당 값으로 바뀜)

컴파일러에 의해 타입 검사가 일어나지 않는다.

또한 파일 전체에서 사용할 수 있다.

 

const 키워드

#import <Foundation/Foundation.h>

int main() {
   const int  LENGTH = 10;
   const int  WIDTH  = 5;
   const char NEWLINE = '\n';
   int area;  
   
   area = LENGTH * WIDTH;
   NSLog(@"AREA : %d", area);
   NSLog(@"%c", NEWLINE);

   return 0;
}

 

똑같은 변수 정의이기에 타입을 지정해줘야 한다. (컴파일러 타입 검사 받음)

또한 블록 스코프에 따라 사용 범위가 달라진다.

 

const가 타입검사도 받을 수 있기에 안전하지만, 주로 파일 전체에서 계속 사용하는 값은 

define으로 정의하고 내부에서 사용하는 경우에는 const를 사용하면 되겠다. 

어떤 것이 더 권장된다기 보다는 상황에 따라 다름!