SW 전공

SW 전공 이론 학습

이론 목록으로 돌아가기

자료형과 연산자, 형변환

C·Java·Python의 자료형, 연산자 우선순위, 형변환과 오버플로를 코드 판독 중심으로 학습한다.

예상 읽기 9

1. 자료형이 필요한 이유

자료형은 값의 표현 범위, 저장 방식, 허용 연산, 메모리 사용량을 결정한다. 같은 비트열도 자료형에 따라 정수, 실수, 문자, 주소 등으로 다르게 해석된다.

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
소스의 리터럴·변수
        │
        ▼
   자료형 결정
        │
        ├─ 저장 크기와 표현 범위
        ├─ 가능한 연산
        ├─ 형변환 규칙
        └─ 결과 자료형

다음 경계를 구분한다.

  • 정수와 실수 연산 결과
  • 정수 나눗셈과 나머지
  • 암시적·명시적 형변환
  • 부호 있는 정수와 부호 없는 정수
  • 연산자 우선순위와 단락 평가
  • 오버플로·정밀도 손실

2. C·Java·Python의 자료형 비교

구분CJavaPython
정수char, short, int, longbyte, short, int, longint
실수float, doublefloat, doublefloat
문자정수형 문자 코드로 처리char는 UTF-16 코드 단위길이 1인 str
논리C99 이후 _Bool, 일반식에서는 0/비0booleanbool
문자열문자 배열 또는 포인터String 객체str 객체
타입 결정정적 타입정적 타입동적 타입

C의 정수 자료형 크기는 표준이 최소 범위와 순서 관계를 정하고, 실제 크기는 구현에 따라 달라질 수 있다. Java의 기본 정수형 크기는 언어 사양에서 고정되어 있다. Python의 정수는 일반적인 기계어 정수보다 큰 값까지 표현할 수 있지만 메모리 한계는 존재한다.

3. 정수 표현과 오버플로

n비트 부호 없는 정수의 범위는 0 ~ 2^n - 1이다. 일반적인 2의 보수 기반 n비트 부호 있는 정수의 범위는 -2^(n-1) ~ 2^(n-1)-1이다.

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
8비트 unsigned: 0  ~ 255
8비트 signed  : -128 ~ 127

Java의 정수 연산은 정해진 비트 폭을 넘어가면 하위 비트만 남는 방식으로 순환한다. 반면 C에서 부호 있는 정수 오버플로는 정의되지 않은 동작이므로 특정 결과가 반드시 나온다고 가정하면 안 된다. 부호 없는 정수는 모듈러 연산처럼 순환한다.

JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
int x = Integer.MAX_VALUE;
System.out.println(x + 1); // -2147483648

Python의 int는 고정 폭이 아니므로 같은 방식의 정수 오버플로는 일반적으로 발생하지 않는다.

4. 실수 표현과 정밀도

부동소수점은 제한된 비트로 실수를 근사한다. 따라서 10진 소수 중 일부는 2진 부동소수점으로 정확히 표현할 수 없다.

PYTHON코드 영역 안에서 좌우로 이동할 수 있습니다.
print(0.1 + 0.2 == 0.3)  # False가 될 수 있다.

실수 비교에서는 문제 목적에 따라 허용 오차를 사용한다.

PYTHON코드 영역 안에서 좌우로 이동할 수 있습니다.
a = 0.1 + 0.2
print(abs(a - 0.3) < 1e-9)  # True

5. 연산자 종류와 우선순위

종류대표 연산자핵심
산술+ - * / %정수·실수 자료형에 따라 결과가 달라진다.
비교< <= > >= == !=결과는 참·거짓이다.
논리`&&
비트`&^ ~ << >>`
대입= += -= *=오른쪽 계산 후 왼쪽에 저장한다.
조건조건 ? 참값 : 거짓값C·Java의 삼항 연산자이다.

일반적인 우선순위의 큰 흐름은 다음과 같다.

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
괄호·호출
   ↓
단항 연산
   ↓
곱셈·나눗셈·나머지
   ↓
덧셈·뺄셈
   ↓
이동 연산
   ↓
비교·동등
   ↓
비트 연산
   ↓
논리 AND·OR
   ↓
조건·대입

괄호로 의도를 명확히 표현하고, 괄호가 없는 식은 단계별로 분해해 평가 순서를 확인한다.

6. 정수 나눗셈과 나머지

C코드 영역 안에서 좌우로 이동할 수 있습니다.
int a = 7 / 2;       // 3
double b = 7 / 2;    // 3.0: 나눗셈이 먼저 정수로 수행됨
double c = 7 / 2.0;  // 3.5
JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
int x = 7 / 2;             // 3
double y = (double) 7 / 2; // 3.5
PYTHON코드 영역 안에서 좌우로 이동할 수 있습니다.
print(7 / 2)   # 3.5: 일반 나눗셈
print(7 // 2)  # 3: 몫 연산
print(7 % 2)   # 1

음수의 몫과 나머지는 언어 규칙이 다를 수 있으므로 언어를 확인해야 한다. Python의 //는 음의 무한대 방향으로 내림한다.

7. 형변환

형변환은 값의 자료형을 다른 자료형으로 바꾸는 과정이다.

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
피연산자 자료형 확인
        │
        ▼
  연산을 위한 승격
        │
        ▼
   연산 결과 생성
        │
        ▼
  대입 대상형으로 변환
  • 확대 변환: 표현 범위가 넓은 형으로 이동한다. 일반적으로 정보 손실 가능성이 작다.
  • 축소 변환: 표현 범위가 좁은 형으로 이동한다. 값 손실이나 잘림 가능성이 있다.
  • 명시적 변환: 프로그래머가 캐스트를 작성한다.
  • 암시적 변환: 언어 규칙이 자동으로 변환한다.
JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
int i = 10;
double d = i;       // 확대 변환
int n = (int) 3.9;  // 3, 소수부 절삭
C코드 영역 안에서 좌우로 이동할 수 있습니다.
double d = 3.9;
int n = (int)d;     // 일반적으로 3

Python은 변수 자체의 고정 자료형을 바꾸는 것이 아니라 변환 함수가 새 객체를 만든다.

PYTHON코드 영역 안에서 좌우로 이동할 수 있습니다.
n = int("42")
s = str(42)
f = float("3.5")

8. 단락 평가

논리식은 결과가 이미 확정되면 뒤의 피연산자를 평가하지 않을 수 있다.

C코드 영역 안에서 좌우로 이동할 수 있습니다.
if (p != NULL && p->value > 0) {
    /* p가 NULL이면 오른쪽을 평가하지 않는다. */
}
PYTHON코드 영역 안에서 좌우로 이동할 수 있습니다.
items = []
if items and items[0] > 0:
    print("positive")

단락 평가는 안전한 조건 검사에 활용되지만, 오른쪽 식의 부수효과에 의존하면 코드를 이해하기 어려워진다.

9. 코드 판독 절차

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
① 변수의 선언 자료형 표시
② 리터럴 자료형 확인
③ 괄호와 우선순위대로 부분식 계산
④ 암시적 승격·형변환 적용
⑤ 정수 나눗셈·오버플로·정밀도 확인
⑥ 대입 후 최종 자료형과 값 기록

10. 정수 승격과 혼합 연산

작은 정수형은 연산 전에 더 큰 정수형으로 승격될 수 있다. Java에서 byte, short, char의 산술 결과는 일반적으로 int가 된다.

JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
byte a = 10, b = 20;
// byte c = a + b;  // 컴파일 오류: a+b의 형은 int
int c = a + b;      // 30

복합 대입은 연산 뒤 대상형으로의 암시적 축소 변환을 포함한다.

JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
byte x = 120;
x += 10;            // (byte)(x + 10)과 유사, 결과 -126

C에서도 charshort는 정수 승격을 거친다. 부호 있는 형과 부호 없는 형을 섞으면 예상과 다른 비교 결과가 나올 수 있으므로, 문제에서 비트 폭과 형을 먼저 표시해야 한다.

11. 비트 이동과 마스크

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
비트 k 설정: x |  (1 << k)
비트 k 해제: x & ~(1 << k)
비트 k 검사: (x & (1 << k)) != 0
비트 k 반전: x ^  (1 << k)

Java의 >>는 부호를 유지하는 산술 이동이고, >>>는 왼쪽을 0으로 채우는 논리적 오른쪽 이동이다. C에서는 음수인 부호 있는 정수의 이동과 표현 범위 밖 왼쪽 이동이 이식성 문제나 정의되지 않은 동작을 만들 수 있으므로 비트 연산에는 부호 없는 형을 쓰는 것이 안전하다.

JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
System.out.println(-8 >> 1);   // -4
System.out.println(-8 >>> 1);  // 2147483644

12. 평가 순서와 부수효과

같은 식 안에서 한 변수를 여러 번 변경하면 언어별 규칙이 크게 다르다.

JAVA코드 영역 안에서 좌우로 이동할 수 있습니다.
int i = 1;
int y = i++ + ++i;  // Java는 피연산자를 왼쪽부터 평가: y=4, i=3

C에서 i++ + ++i처럼 순서가 정해지지 않은 변경을 겹치면 정의되지 않은 동작이므로 특정 출력값을 계산하지 않는다. 코드를 해석할 때는 언어가 무엇인지, 평가 순서가 규정되어 있는지, 한 변수의 변경과 읽기가 충돌하는지를 먼저 확인한다.

13. 형변환 경계 판독

표현결과 원리
Java (int)-3.90 방향으로 소수부를 버려 -3
Python int(-3.9)0 방향으로 변환해 -3
Python math.floor(-3.9)음의 무한대 방향으로 내려 -4
Java byte b=(byte)130하위 8비트만 남아 -126

실수에서 정수로 바꾸는 규칙과 정수 나눗셈의 규칙은 별개다. 또한 C에서 표현할 수 없는 실수를 정수형으로 변환하는 상황은 이식 가능한 단일 결과로 단정하지 않는다.

확인 문제

  1. Java에서 byte a=10, b=20;일 때 a+b의 결과 자료형은 무엇인가?
  2. Java에서 int x=-8;일 때 x >>> 1의 값은 무엇인가?
  3. 정수 x의 k번째 비트를 0으로 만드는 일반적인 비트식은 무엇인가?
  4. Java에서 (int)-3.9와 Python에서 math.floor(-3.9)의 결과는 각각 무엇인가?
  5. C에서 i++ + ++i의 결과를 특정 값으로 계산하면 안 되는 이유는 무엇인가?