C 언어의 로직 쇼트 서킷과 구조체 메모리 분석

논리 연산자의 쇼트 서킷(Short Circuit) 현상

C 언어에서 &&|| 연산자는 쇼트 서킷 평가(Short-circuit evaluation) 방식을 사용합니다. 이는 첫 번째 피연산자만으로 전체 결과가 확정되면 두 번째 피연산자를 평가하지 않는 특성입니다.

다음 코드는 흔히 발생하는 오류 사례입니다:

// 문제가 있는 코드: b가 0일 때 a % b 연산에서 SIGSEGV 발생
if (temp == 3 && (a % b != 0 || b == 0)) {
    printf("go");
}

위 코드에서 temp == 3이 참일 경우 (a % b != 0 || b == 0)이 평가됩니다. 그런데 || 연산자는 왼쪽부터 평가하므로 a % b != 0을 먼저 검사합니다. 만약 b가 0이라면 0으로 나누기 연산이 발생하여 SIGSEGV 신호가 발생합니다.

올바른 코드는 다음과 같이 조건 순서를 변경해야 합니다:

// 수정된 코드: b가 0인 경우를 먼저 검사
if (temp == 3 && (b == 0 || a % b != 0)) {
    printf("go");
}

이제 ||의 왼쪽에서 b == 0을 먼저 검사하므로, b가 0이라면 쇼트 서킷에 의해 a % b != 0은 평가되지 않습니다.

구조체 메모리 레이아웃 분석

C 구조체는 내부 변수들이 선언 순서대로 연속적인 메모리 공간에 배치되며, 구조체 자체의 메타데이터(크기 등)를 포함하지 않습니다. 다음 코드를 통해 이를 확인할 수 있습니다:

#include <stdio.h>

typedef struct {
    int a;
    int b;
    int c;
    int d;
} TD;

int main(void) { 
    TD data;
    TD *dataPtr = &data;
    
    dataPtr->a = 0xA00AA11A;
    dataPtr->b = 0xB00BB22B;
    dataPtr->c = 0xC00CC33C;
    dataPtr->d = 0xD00DD44D;
    
    printf("int 크기: %d 바이트\n", (int)sizeof(int));
    printf("포인터 크기: %d 바이트\n", (int)sizeof(int *));
    
    // 구조체 전체를 8바이트 단위로 읽기
    printf("시작 주소 데이터: %llX\n", *(unsigned long long *)dataPtr);
    
    // 포인터 연산으로 각 멤버 접근
    int *intPtr = (int *)dataPtr;
    printf("멤버 a: %X\n", *(intPtr + 0));
    printf("멤버 b: %X\n", *(intPtr + 1));
    printf("멤버 c: %X\n", *(intPtr + 2));
    printf("멤버 d: %X\n", *(intPtr + 3));
    
    // 각 멤버의 주소 출력
    printf("a 주소: %p\n", &data.a);
    printf("b 주소: %p\n", &data.b);
    printf("c 주소: %p\n", &data.c);
    printf("d 주소: %p\n", &data.d);
    
    return 0;
}

실행 결과:

int 크기: 4 바이트
포인터 크기: 8 바이트
시작 주소 데이터: B00BB22BA00AA11A
멤버 a: A00AA11A
멤버 b: B00BB22B
멤버 c: C00CC33C
멤버 d: D00DD44D
a 주소: 0x7ffe7b2715b0
b 주소: 0x7ffe7b2715b4
c 주소: 0x7ffe7b2715b8
d 주소: 0x7ffe7b2715bc

주요 발견점

  • 구조체의 시작 주소와 첫 번째 멤버(a)의 주소가 동일합니다.
  • int 멤버는 4바이트 간격으로 연속 배치됩니다.
  • 구조체는 단순히 멤버 변수들의 연속된 메모리 블록으로, 구조체 자체의 크기 정보를 저장하지 않습니다.
  • 포인터 캐스팅을 통해 구조체를 정수 배열처럼 접근할 수 있습니다.

참고: 구조체 메모리 정렬(Alignment)에 대한 상세 내용은 "C Primer Plus" 서적을 참조하세요. 실제로는 컴파일러가 성능 최적화를 위해 패딩 바이트를 추가할 수 있습니다.

태그: C short-circuit struct memory-layout pointer-arithmetic

6월 8일 03:05에 게시됨