반응형

구조체 정의

 

 

지금까지 학습하면서 자료를 저장할 공간이 필요하면 변수를 선언하여 자료를 저장했다.

 

만약 여러 개의 변수를 묶어서 사용해야 하는 경우 배열을 사용해서 문제를 해결할 수 있다.

 

하지만 배열 오직 같은 자료형으로만 묶어 선언하여 사용할 수 있다는 단점이 있다.

 

이러한 단점을 보완하기 위해 만들어진 게구조체이다.

 

 

구조체 하나 이상의 변수를 묶어 새로운 자료형을 정의하는 것으로

 

구조체 배열과 다르게 서로 다른 자료형을 묶는 것이 가능하다.

 

또한

 

구조체 배열 등 구조체의 멤버로 묶어 구조체를 정의할 수 있다.

 

구조체를 정의하는 문법은 아래와 같다.

 

-

 

 

-

 

다음 내용은 문자형 변수 a 정수형 변수 b를 묶어 새로운 구조체 자료형 data를 만드는 예제이다.

 

-

 

 

-

 

이때 변수 a와 b는 각각 구조체 data의 멤버(member)라고 한다.

 

구조체 변수를 선언하는 방법은 크게

 

1. 구조체를 정의하면서 변수를 함께 만드는 방법

 

2. 구조체를 정의한 뒤에 구조체 변수를 선언하는 방법

 

이렇게 두 가지로 나뉜다.

 

아래의 예시는 1번째 방법이다.

 

-

 

 

-

 

위의 내용은 구조체 data를 정의하면서 구조체 변수 data_type_1과 data_type_2를 선언하는 내용이다.

 

다음의 예제를 통해 2번째 방법을 봐보자.

 

-

 

 

 

-

 

위의 내용은 구조체 타입 data를 정의한 뒤에 data_type_1 data_type_2를 선언하는 내용이다.

 

 

아래의 예제는 문자형 변수 a 정수형 변수 b를 묶어 새로운 구조체 자료형 data를 정의한 뒤에

 

구조체가 사용하는 메모리 크기를 출력하고

 

구조체 멤버에 값을 대입하여 저장된 값을 출력하는 예제이다.

 

-

 

test43.c
0.00MB

 

 

 

-

 

구조체의 멤버에 접근하기 위해서 '.'(dot) 연산자를 사용했으며

 

'.' 연산자 해당 구조체의 멤버를 참조한다는 의미이다.

 

-

 

 

-

 

위와 같은 구문을 통해서 구조체 data의 멤버 a와 b에 값을 저장했으며

 

printf 문에서 구조체의 멤버에 접근하여 값을 참고하기 위해서 값을 저장할 때와 같이

 

'.' 연산자를 사용하여 값을 참조했다.

 

 

위의 결과에서 흥미로운 부분이 있는데

 

다음과 같은 문장에서 구조체의 크기를 출력한 결과 8byte라는 점이다.

 

-

 

 

-

 

위의 구문에서 구조체 data의 크기를 출력하기 전

 

문자형(char) 정수형(int) 자료형의 크기를 출력해 보면

 

각각 1byte와 4byte 값이 출력되는데

 

 두 자료형 변수를 묶어서 새로운 구조체 data를 만들면

 

당연히 5바이트가 되어야 하는 것이 일반적인 생각이다.

 

하지만

 

실행 결괏값은 윈도우 환경에서 기본 설정 값으로 VisualStudio를 이용해 컴파일한 실행 결과

 

리눅스에서 gcc를 이용하여 컴파일한 실행 결과가 모두 8byte라는 결과로 같을 것이다.

 

 

이처럼 실제 자료형보다 큰 크기의 메모리가 할당된 이유

 

소스 코드를 컴파일할 때 해당 구조체의 크기를 정렬하여 컴파일하기 때문이다.

 

이를 구조체 멤버 정렬(struct member alignment)라고 한다.

 

 

소스 코드를 컴파일할 때 구조체 멤버 정렬이 발생하는 이유

 

CPU에서 메모리에 접근할 때 특정 사이즈로 접근해야 더욱 속도가 빠르므로

 

컴파일러가 성능 향상을 위해 최적화하기 때문이다.

 

멤버 정렬을 하면서 정렬 사이즈 단위에 부족하면 부족한 해당 바이트 값만큼

 

패딩(padding)을 추가하여 정렬 사이즈를 맞춘다.

 

 

구조체 멤버 정렬로 최적화하여 컴파일된 경우에는 프로그램 실행 속도를 높일 수 있지만

 

통신 프로토콜 구조체를 만들어 사용하는 경우 등에는 프로그램 실행에 악영향을 줄 수 있다.

 

따라서 구조체의 크기가 정확하게 계산되어야 하며

 

구조체 멤버 정렬을 1byte 단위로 하거나 해당 기능을 사용하지 말아야 한다.

 

 

윈도우 환경에서 VisualStudio를 이용하여 프로그램을 개발하는 경우

 

구조체 멤버 정렬을 1byte 단위로 사용하기 위해서는 

 

프로젝트 속성의 [구성 속성]-[C/C++]-[코드 생성] 메뉴에서

 

[구조체 멤버 맞춤]이라는 항목에서 [기본값]을 [1바이트(Zp1)]로 변경하거나

 

다음과 같이 해당 구조체 선언 앞 #pragma pack(1) 문장을 추가하여

 

1byte 단위 구조체 정렬을 실행해야 한다는 사실을 컴파일러에게 미리 알려 주어야 한다.

 

-

 

 

-

 

프로그램을 실행할 때 속도 저하를 막기 위해 특정한 구조체 정의에 한하여

 

구조체 멤버 정렬 값을 변경할 수도 있는데

 

이 경우는 다음과 같은 내용을 추가해 주면 된다.

 

-

 

 

 

-

 

위의 내용은 기존의 byte를 스택에 push 하고1byte 단위 구조체 멤버 정렬을 설정한 다음

 

끝나는 부분에 원래의 byte 단위를 pop 해주는 설정 코드이다.

 

보통은 이와 같은 방법을 사용하면 될 것이다.

 

 

리눅스 환경에서 gcc를 이용하여 개발하는 환경이면 다음과 같이 구조체를 정의할 때

 

패딩(padding) 없이 채운다는 의미의 속성으로 __attribute__((packed))를

 

추가하여 구조체 변수를 정의한다.

 

-

 

 

-

 

다음의 예제는 위의 예제 test43.c을 수정하여

 

실제 데이터 크기만큼 구조체 크기를 메모리에 할당할 수 있도록 수정한 예제이다.

 

__linux__ 매크로 정의 여부를 확인하도록 하여

 

윈도우 및 리눅스 환경에 따라 소스 코드가 달리 컴파일되게 된다.

 

다음의 예제를 컴파일하여 실행해보면 우리가 처음 예상했던 구조체 크기가 출력된다는 것을 알 수 있다.

 

-

 

test44.c
0.00MB

 

 

 

-

 

앞으로 학습할 예제에서 특별한 언급이 없으면 기본 컴파일 설정으로 예제를 학습하도록 하며

 

나중에 프로토콜 헤더 구조체를 정의하는 등

 

구조체 크기가 중요한 경우 다시 한번구조체 멤버 정렬에 대해 설명하도록 한다.

반응형

'시작하지 말았어야 했던 것 > C언어 기본 문법' 카테고리의 다른 글

23. 비트 필드  (0) 2021.02.01
22. 구조체 초기화  (0) 2021.02.01
20. 조건부 컴파일  (0) 2021.02.01
19. 매크로 연산자  (0) 2021.02.01
18. 매크로 함수  (0) 2021.02.01

+ Recent posts