공용체와 구조체 비트필드 |
공용체 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 |
구조체 비트필드
- 구조체 메모리 접근을 원하는 비트 단위로 접근 허용하는 것
- 불필요하게 많은 메모리를 사용하는 것을 방지하며 메모리를 효율적으로 활용하기 위해 비트로 표현
- 자료형은 int, char형의 unsigned를 사용하며, 멤버명 옆에 : 과 함께 비트 크기 지정
5 struct BIT |
sizeof(tmp): 1 // 1Byte = 1bit * 8이므로 |
20 union mytype |
=> 1Bytesizeof(mych): 1 // 공용체이므로 가장 큰 자료형의 크기만큼 메모리 공간 할당 |
5 struct BIT |
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 |
※ 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 |
※ 운영체제에 따른 메모리 저장방식
문제발생운영체제에 따른 메모리 저장방식
데이터를 할당된 메모리에 저장시
- 리틀엔디안 : 할당한 메모리에 최하위 바이트부터 데이터를 저장
- 빅엔디안 : 할당한 메모리에 최상위 바이트부터 데이터를 저장
예시
long int N = 0x1234567
- 리틀엔디안 표현 방식 : 78 56 34 12 (INTEL계열)
[ INTEL ]
- 빅엔디안 표현 방식 : 12 34 56 78 (UNIX 계열)
union size : 4 |
바이트 오더링 활용 예제 : 네트워크 통신
[ 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;
}
- 호스트 바이트 오더링 순서와 네트워크(빅엔디안 구조) 바이트 오더링 순서와 같음!
더 많은 시리즈 보기
[고급 C++]C컴파일러와 C라이브러리(공유/정적/동적라이브러리)
[고급 C++]포인터 1편(프로세스/포인터변수/포인터연산/NULL포인터)
[고급 C++]포인터 3편(배열 포인터/포인터 배열/문자열 상수 포인터)
[고급 C++]포인터 4편(다중 포인터/함수 포인터/void형 포인터)
[고급 C++] 가변인자 / CERT C (feat. 안전 코딩하기)
궁금한 사항은 댓글로 남겨주세요💃💨💫
좋아요와 구독(로그인X)은 힘이 됩니다 🙈🙉
'컴퓨터공학과 > Programming' 카테고리의 다른 글
[고급 C++] 매크로함수 (0) | 2020.11.02 |
---|---|
[고급 C++] 비트연산자 (0) | 2020.11.02 |
[고급 C++] 구조체와 구조체포인터 (0) | 2020.10.27 |
[고급 C++] 가변인자 / CERT C (feat. 안전 코딩하기) (1) | 2020.10.26 |
[고급 C++]포인터 4편(다중 포인터/함수 포인터/void형 포인터) (1) | 2020.10.23 |