[고급 C++] 공용체와 구조체 비트필드 + 바이트 오더링 / 활용방안

 

 

  공용체와 구조체 비트필드

 

공용체 UNION

- 차례대로 메모리 할당되는 구조체와 달리 같은 메모리 공간을 여러 멤버가 공유하는 사용자 정의 자료형

- 구조체와 메모리 할당구조가 다름

- 가장 큰  자료형의 크기만큼 메모리 공간이 할당되며 모든 멤버는 시작주소가 동일

- 하드웨어 제어시 애용

#include <stdio.h>
int main()
{
	union UNI { 
		char x;
		short int y;
		long int z;
	} uni;

	printf("union size : %d\n", sizeof(uni));
	printf("%p, %p, %p \n", &uni.x, &uni.y, &uni.z);

	uni.z = 0x12345678;
	
	printf("%x %x %x \n", uni.x, uni.y, uni.z);

	return 0;
}

union size : 4
7ffff100, 7ffff100, 7ffff100    // 모든 멤버의 시작주소 동일
12 1234 12345678                 // 자료형 크기만큼 값을 가짐

 

구조체 비트필드

- 구조체 메모리 접근을 원하는 비트 단위로 접근 허용하는 것

- 불필요하게 많은 메모리를 사용하는 것을 방지하며 메모리를 효율적으로 활용하기 위해 비트로 표현

- 자료형은 int, char형의 unsigned를 사용하며, 멤버명 옆에 : 과 함께 비트 크기 지정

     5     struct BIT
     6     {
     7        unsigned char bit0:1;
     8      unsigned char bit1:1;
     9        unsigned char bit2:1;
    10        unsigned char bit3:1;
    11        unsigned char bit4:1;
    12        unsigned char bit5:1;
    13        unsigned char bit6:1;
    14        unsigned char bit7:1;
    16     } tmp;
    17
    18     printf("sizeof(tmp): %d \n", sizeof(tmp));

sizeof(tmp): 1          // 1Byte = 1bit * 8이므로

    20     union mytype
    21     {
    22        char ch;
    23        struct BIT bits;
    24     } mych;
    25
    26     printf("sizeof(mych): %d \n", sizeof(mych));

=>  1Bytesizeof(mych): 1          // 공용체이므로 가장 큰 자료형의 크기만큼 메모리 공간 할당

     5     struct BIT
     6     { 
     7        unsigned char bit0:1;
     8      unsigned char bit1:1;
     9        unsigned char bit2:1;
    10        unsigned char bit3:1;
    11        unsigned char bit4:1;
    12        unsigned char bit5:1;
    13        unsigned char bit6:1;
    14        unsigned char bit7:1;
    15        unsigned char bit:1;
    16     } tmp;
    17
    18     printf("sizeof(tmp): %d \n", sizeof(tmp));

sizeof(tmp): 2          //  1bit * 9 (char 할당 후 bit 채운 후 메모리 부족하면 다시 char 할당)

 

활용 예시1 : 이진수 출력 코드

#include <stdio.h>
int main()
{
	struct BIT
	{
		unsigned char bit0:1;
		unsigned char bit1:1;
		unsigned char bit2:1;
		unsigned char bit3:1;
		unsigned char bit4:1;
		unsigned char bit5:1;
		unsigned char bit6:1;
		unsigned char bit7:1;
	} tmp;

	printf("sizeof(tmp): %d \n", sizeof(tmp));

	union mytype
	{
		char ch;
		struct BIT bits;
	} mych;

	printf("sizeof(mych): %d \n", sizeof(mych));

	while(1)
	{
		printf("문자 ? ");
		mych.ch = getchar();
		fflush(stdin);

		if(mych.ch=='q')
		break;	
		printf("%d : ", mych.ch);
 
		//ch 멤버의 2진수 출력 코드추가
		printf("%d ", mych.bits.bit0);
		printf("%d ", mych.bits.bit1);
		printf("%d ", mych.bits.bit2);
		printf("%d ", mych.bits.bit3);
		printf("%d ", mych.bits.bit4);
		printf("%d ", mych.bits.bit5);
		printf("%d ", mych.bits.bit6);
		printf("%d ", mych.bits.bit7);
		printf("\n");
	}

	return 0;
}

sizeof(tmp): 1
sizeof(mych): 1
문자 ? A
65 : 0 1 0 0 0 0 0 1
문자 ? a
97 : 0 1 1 0 0 0 0 1
문자 ? B
66 : 0 1 0 0 0 0 1 0
문자 ? Z
90 : 0 1 0 1 1 0 1 0
문자 ? z
122 : 0 1 1 1 1 0 1 0
문자 ? q

※ unsigned int : 32비트를 전부 데이터로 쓸게

     signed int 는 첫비트는 부호비트 + 31비트의 데이터

 

 

활용예제2 : IP주소 클래스별 구분

#include <stdio.h>

#define UINT4 unsigned int

typedef struct{
	UINT4   ClassA : 8;
	UINT4   ClassB : 8;
	UINT4   ClassC : 8;
	UINT4   ClassD : 8;
} BitIpAddr;

typedef union {
	UINT4  Ip;
	BitIpAddr BitIp;
} IpAddr;

void IpAddr_func(IpAddr *IpAddress, UINT4 Ip)
{
	IpAddress->Ip = Ip;
	printf("\nIp : %#x, IpAddress->Ip : %#x\n\n", lp, IpAddress->Ip);

	printf("IpAddress->BitIp.ClassA :(%#x), (%d) \n", IpAddress->BitIp.ClassA, IpAddress->BitIp.ClassA);
	printf("IpAddress->BitIp.ClassB :(%#x),(%d) \n", IpAddress->BitIp.ClassB, IpAddress->BitIp.ClassB);
	printf("IpAddress->BitIp.ClassC :(%#x), (%d) \n", IpAddress->BitIp.ClassC, IpAddress->BitIp.ClassC);
	printf("IpAddress->BitIp.ClassD :(%#x), (%d) \n", IpAddress->BitIp.ClassD, IpAddress->BitIp.ClassD);
}

int main()
{
	IpAddr ipaddress;
	IpAddr_func( &ipaddress, 0x460CDC21); // == 70.12.220.33:

	return 0;
 }

Ip : 0x460cdc21, IpAddress->Ip : 0x460cdc21
IpAddress->BitIp.ClassA :(0x46), (70)
IpAddress->BitIp.ClassB :(0xc),(12)
IpAddress->BitIp.ClassC :(0xdc), (220)
IpAddress->BitIp.ClassD :(0x21), (33)

 

※ 운영체제에 따른 메모리 저장방식

문제발생운영체제에 따른 메모리 저장방식

데이터를 할당된 메모리에 저장시

- 리틀엔디안 : 할당한 메모리에 최하위 바이트부터 데이터를 저장

- 빅엔디안 : 할당한 메모리에 최상위 바이트부터 데이터를 저장

 

예시

long int N = 0x1234567 

 

- 리틀엔디안 표현 방식 : 78 56 34 12 (INTEL계열)

[ INTEL ]

인텔 - 리틀엔디안 표기

 

- 빅엔디안 표현 방식 : 12 34 56 78 (UNIX 계열)

union size : 4
7ffff100, 7ffff100, 7ffff100    // 주소 다 같다!! 시작주소가 다 같아
12 1234 12345678             // 자료형 크기만큼 써

 

바이트 오더링 활용 예제 : 네트워크 통신

[ INTEL ]

#include <stdio.h>
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")

int main (int argc, char * argv[])
{
   unsigned short host_port = 0x1234;       //2byte 데이터 저장
   unsigned short net_port;
   unsigned long host_addr = 0x12345678;  //4byte 데이터 저장
   unsigned long net_addr;

   net_port = htons(host_port);    	      //리틀엔디안에서 빅 엔디안 방식으로 net_port 에 저장
   net_addr = htonl(host_addr);             //리틀엔디안에서 빅 엔디안 방식으로 net_addr 에 저장

   printf("\nHost ordered port : %#x \n" , host_port);
   printf("Network ordered port : %#x \n" , net_port);
   printf("Host ordered address : %#lx \n", host_addr);
   printf("Network ordered address : %#lx \n" , net_addr);

   printf("\nhost_addr. \n");
   printf("%p : %x\n", &host_addr, *(char *)&host_addr);
   printf("%p : %x\n", ((char*)&host_addr+1), *((char *)&host_addr+1));
   printf("%p : %x\n", ((char*)&host_addr+2), *((char *)&host_addr+2));
   printf("%p : %x\n", ((char*)&host_addr+3), *((char *)&host_addr+3));

   printf("\nnet_addr. \n");
   printf("%p : %x\n", &net_addr, *(char *)&net_addr);
   printf("%p : %x\n", ((char*)&net_addr+1), *((char *)&net_addr+1));
   printf("%p : %x\n", ((char*)&net_addr+2), *((char *)&net_addr+2));
   printf("%p : %x\n", ((char*)&net_addr+3), *((char *)&net_addr+3));

   return 0;

}

 

 

[ UNIX ]

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main (int argc, char * argv[])
{
	unsigned short host_port = 0x1234; //2byte 데이터 저장
	unsigned short net_port;
	unsigned long host_addr = 0x12345678;   //4byte 데이터 저장
	unsigned long net_addr;

	net_port = htons(host_port);   //리틀엔디안에서 빅 엔디안 방식으로 net_port 에 저장
	net_addr = htonl(host_addr);  //리틀엔디안에서 빅 엔디안 방식으로 net_addr 에 저장

	printf("\nHost ordered port : %#x \n" , host_port);
	printf("Network ordered port : %#x \n" , net_port);
	printf("Host ordered address : %#lx \n", host_addr);
	printf("Network ordered address : %#lx \n" , net_addr);

	printf("\nhost_addr. \n");
	printf("%p : %x\n", &host_addr, *(char *)&host_addr);
	printf("%p : %x\n", ((char*)&host_addr+1), *((char *)&host_addr+1));
	printf("%p : %x\n", ((char*)&host_addr+2), *((char *)&host_addr+2));
	printf("%p : %x\n", ((char*)&host_addr+3), *((char *)&host_addr+3));

	printf("\nnet_addr. \n");
	printf("%p : %x\n", &net_addr, *(char *)&net_addr);
	printf("%p : %x\n", ((char*)&net_addr+1), *((char *)&net_addr+1));
	printf("%p : %x\n", ((char*)&net_addr+2), *((char *)&net_addr+2));
	printf("%p : %x\n", ((char*)&net_addr+3), *((char *)&net_addr+3));

	return 0;
}

- 호스트 바이트 오더링 순서와 네트워크(빅엔디안 구조) 바이트 오더링 순서와 같음!

 

 


 

 

 

 

궁금한 사항은 댓글로 남겨주세요💃💨💫
좋아요와 구독(로그인X)은 힘이 됩니다 🙈🙉

 

반응형
그리드형

댓글

❤️김세인트가 사랑으로 키웁니다❤️