본문 바로가기

프로그래밍/C67

winmm API 사용하여 WAV 파일 재생하기 winmm 은 Windows Multimedia의 약자로 해당 라이브러리의 API를 사용해 WAV 형식의 오디오 파일을 재생할 수 있다.  #include #include // mmsystem.h 포함#include // winmm.lib 링크#pragma comment(lib, "winmm.lib")int main() { // wav 파일 경로 const char* filePath = "C:\\Users\\jo\\Downloads\\warning.wav"; // wav 파일 동기식 재생 MMRESULT result = PlaySound(filePath, NULL, SND_FILENAME); if (!result) { printf("PlaySound Error\n"); return 1; } print.. 2024. 7. 4.
POSIX thread, mutex 사용법 Pthread는 모든 유닉스 계열 POSIX 시스템에서, 일반적으로 이용되는 라이브러리로 병렬적으로 작동하는 소프트웨어 작성을 위해 사용할 수 있다. 소스코드에선 #include 로 헤더를 포함하고 컴파일 시 -pthread 옵션을 붙여 컴파일 한다.   주요 thread 함수  pthread_create새로운 스레드를 생성하고 지정된 함수 start_routine을 실행한다.int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);pthread_t *thread: 생성된 스레드의 식별자를 저장할 포인터, 해당 식별자를 통해 이후 스레드를 제어할 수 있다.const .. 2024. 6. 26.
C] epoll 사용법 epoll이란?epoll은 리눅스 커널 2.5.44부터 도입된 Multiplexing IO 함수로 다수의 파일 디스크립터를 모니터링 할 때 효율적이다. epoll은 epoll_event 구조체와 다음의 세 가지 주요 함수로 구성된다.epoll_create : epoll 파일 디스크립터 저장소 생성epoll_ctl : 저장소에 파일 디스크립터 등록 및 삭제epoll_wait : 파일 디스크립터의 변화를 대기   select와의 차이점select의 경우 매번 호출할 때마다 파일 디스크립터 집합을 사용자 공간에서 커널 공간으로 복사해야 하지만 epoll는 한 번 설정한 파일 디스크립터 집합을 커널 공간에서 유지하여 불필요한 복사를 방지한다. 따라서 많은 수의 파일 디스크립터를 다룰 때 epoll이 더욱 효율적.. 2024. 6. 24.
__DATE__ 에서 필요한 정보를 추출하여 원하는 포맷으로 출력하기 __DATE__, __TIME__ 은 ANSI/ISO 표준으로 정의되고 C 컴파일러 전처리기가 제공하는 특수한 매크로로 소스파일이 컴파일 시점의 날짜와 시간 정보를 나타내는 문자열 리터럴이다. 보통 __TIME__ 의 경우는 우리가 자주 사용하는 형태와 동일하기 때문에 따로 손댈게 없다. 하지만 __DATE__ 의 경우 월, 일, 년도 순이고 월은 영문에 일은 한자리 수 인경우 앞이 공백이여서 그대로 쓰기엔 애매하다. 따라서 __DATE__를 원하는 형태의 formatted string으로 출력하기 위해 다음의 두가지 방법이 있다. 첫번째 방법 yyyy-mm-dd 로 출력하고자 하는 경우 해당 digit Character를 추출해서 조합하는 형태 #include #define BUILD_YEAR_CH0 .. 2024. 4. 17.
C언어 ] qsort (Quick Sort, 퀵정렬) 함수 사용법 C언어 표준 라이브러리에 포함된 qsort 함수는 퀵 정렬(Quick Sort) 알고리즘을 사용하여 배열을 정렬하는 데에 사용된다. 아래는 qsort 함수의 사용법에 대한 예시이다. 1. 헤더 파일 include qsort 함수를 사용하려면 stdlib.h 헤더 파일을 포함해야 한다. #include 2. 비교 함수 작성 qsort 함수를 사용하기 위해선 정렬을 위해 사용할 비교 함수를 만들어야 하며, 이 함수는 두 요소를 받아들여 비교한 결과를 반환해야 한다. 반환값이 음수, 0, 양수인지에 따라 정렬의 순서가 결정된다. 비교 함수의 반환값이 양수면, qsort 함수는 두 요소의 순서를 바꾼다. int compare(const void *a, const void *b) { // 비교 로직 작성 retu.. 2024. 1. 30.
윈도우 소켓 ] connect() 함수의 타임아웃은 21초 connect() 함수의 타임아웃 TCP connection은 3-way-handshake에 의해 이루어지는데 클라이언트는 SYN 패킷을 전송한 이후 SYN+ACK를 수신할 때까지 대기하게 된다. 이때, 서버기기가 네트워크에 연결되어 있고 포트가 닫혀있는 경우 서버기기는 SYN+ACK 대신 RST 패킷을 보낼테니 클라이언트는 서버에 연결할 수 없다는 걸 RTT(Round Trip Time)만에 알 수 있다. 로컬네트워크에서 이 시간은 몇 밀리초이지만 인터넷에서는 그 이상이 될 수 있다. 서버기기가 네트워크에 없는 경우 클라이언트는 응답을 받지 못한채 SYN 패킷 전송을 재시도할 것이다. 이 때 재시도 횟수와 타임아웃은 운영체제의 TCP/IP protocol stack 설정값에 따라 달라질 수 있는데 윈도.. 2023. 12. 25.
윈도우 소켓 ] blocking / non-blocking 소켓 사용 시 소켓함수의 리턴 조건 recv() Blocking socket : 수신된 데이터가 없으면 블록되고, MSG_WAITALL 플래그를 사용하면 원하는 크기만큼 도착할 때까지 기다릴 수 있다. Non-blocking socket : 수신된 데이터가 없으면 WSAEWOULDBLOCK으로 즉시 리턴한다. WSAGetLastError() 함수를 사용하여 에러 코드를 확인할 수 있다. TCP / UDP 비교 : 동일하게 Blocking socket에서는 소켓 수신 버퍼에 도착한 데이터가 없으면 블록되고, 소켓 수신 버퍼에 도착한 데이터가 있을 시 이를 응용 프로그램이 제공한 버퍼에 복사한 뒤 리턴한다. send() Blocking socket : 소켓 송신 퍼버에 여유 공간이 없으면 블록되고, 응용 프로그램이 전송 요청한 데이터를 소켓 .. 2023. 12. 24.
IcmpSendEcho IcmpSendEcho 함수는 Windows 운영 체제에서 ICMP 에코 요청을 보내고 응답을 받는 데 사용되는 함수로 주로 네트워크 연결 상태를 확인하거나 호스트의 응답 시간을 측정하는 데 사용됩니다. 📝 ICMP (Internet Control Message Protocol) : 네트워크에서 발생하는 여러 상태 및 오류 메시지를 전송하는 데 사용되는 프로토콜 DWORD IcmpSendEcho( HANDLE IcmpHandle, IPAddr DestinationAddress, LPVOID RequestData, WORD RequestSize, PIP_OPTION_INFORMATION RequestOptions, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout .. 2023. 12. 23.
strchr, strrchr strchr 및 strrchr 함수는 C 표준 라이브러리 함수로 문자열에서 특정 문자를 찾는 데 사용되는 함수들이다. strchr 문자열 앞에서 부터 찾고 strrchr 는 뒤에서 부터 찾는다는 차이가 있다. strchr #include char *strchr(const char *str, int c); 문자열에서 특정 문자 c를 찾아 첫 번째로 등장하는 위치를 반환한다다. 만약 문자 c가 문자열에 없으면 NULL을 반환한다. 사용 예시. #include #include int main() { const char *str = "Hello, World!"; char target = ' '; // 문자열에서 ' '공백문자를 찾기 char *result = strchr(str, target); if (resu.. 2023. 12. 22.
strpbrk strpbrk char *strpbrk(const char *str1, const char *str2); str1: 검색 대상이 되는 문자열 str2: 검색할 문자들로 이루어진 문자세트 반환 값: str1에서 str2에 지정된 문자세트 중 첫 번째로 매치되는 문자의 포인터. str1, str2 둘 다 null terminated string이어야 하고 일치여부 확인시 null 문자는 고려하지 않음. 반환값이 NULL이라면 일치하는 문자를 못찾은 것. 사용 예시 #include #include int main() { // str1에서 첫번째로 나오는 모음문자 포인터를 찾음 const char *str1 = "Hello, World!"; const char *str2 = "aeiou"; char *resul.. 2023. 12. 21.
strcspn strcspn size_t strcspn(const char *str1, const char *str2); str1: 검색 대상이 되는 문자열 str2: 검색할 문자들로 이루어진 문자세트 반환 값: str1에서 str2에 지정된 문자세트 중 첫 번째로 매치되는 문자가 위치한 인덱스, 인덱스는 0부터 시작하며 str1, str2 둘 다 null terminated string이어야 하고 일치여부 확인시 null 문자는 고려하지 않음. 반환값이 strlen(str1)이라면 일치하는 문자를 못찾은 것. 사용 예시. #include #include int main() { // str1에서 첫번째로 나오는 모음을 찾음 const char str1[] = "Hello world!"; const char str2[].. 2023. 12. 20.
C/C++ ] ANSI 이스케이프 코드 시퀀스 사용해서 커서 이동 + 터미널 조작하기 C/C++ 콘솔 프로그램에서 ANSI 이스케이프 시퀀스 명령어를 사용하여 콘솔 커서 이동 등 터미널을 조작할 수 있다. 1. 이스케이스 시퀀스 시작 : \x1B[ 또는 \033[를 사용하여 ANSI 이스케이프 시퀀스를 시작한다. 아래서는 \x1B[ 기준으로 설명한다. 2. 커서 이동 커서를 위로 이동 : \x1B[A, \x1B[A 또는 \x1B[1A 는 위로 한칸 이동하고 \x1B[2A 는 위로 두칸 이동한다. 커서를 아래로 이동 : \x1B[B 커서를 오른쪽으로 이동 : \x1B[C 커서를 왼쪽으로 이동 : \x1B[D 특정 위치로 커서 이동 : \x1B[;H, row는 행번호 col은 열번호로 \x1B[0;0H 또는 \x1B[1;1H 는 화면의 좌측 상단 첫번째 칸으로 이동한다. 3. 커서 숨기기/보.. 2023. 12. 11.
윈도우 소켓 ] select 입출력 모델 select 모델 select() 함수는 동기식 다중 입출력함수(Synchronous Multiplexing IO)로 recv(), send() 등 소켓 함수 호출이 성공할 수 있는 시점을 미리 알 수 있다. 따라서 소켓 함수 호출 시 조건을 만족하지 않아 생기는 여러 문제를 해결할 수 있다. 또한 멀티스레드 방식 등 다른 모델과 비교하여 select 모델의 사용상의 장점은 여러 소켓을 한 스레드로 처리할 수 있다는 점이다.     select 모델 사용 준비 select() 모델을 사용하려면 세 종류의 소켓 셋을 준비해야 한다. 읽기셋, 쓰기셋, 예외셋이 있는데 세 종류중에 필요한 소켓셋만 준비해도 된다. 소켓 셋은 소켓의 집합으로 종류에 따라 소켓들을 담아두는 역할을 한다. 예를 들어 어떤 소켓에 대.. 2023. 11. 26.
Win32 API ] 이벤트 / CreateEvent, SetEvent, ResetEvent Windows 프로그래밍에서 이벤트를 생성하고 다루는 함수인 CreateEvent, SetEvent, ResetEvent 와 이벤트 대기 함수인 WaitForSingleObject 를 사용해서 스레드 간 통신 또는 동기화를 수행할 수 있다. CreateEvent() CreateEvent 함수는 이벤트 객체를 생성한다. 이벤트 객체는 signaled, non-signaled 상태가 있는데 SetEvent 함수를 통해 이벤트 신호를 보내거나 WaitForSingleObject 함수를 통해 이벤트 신호를 받을 수 있다. HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR.. 2023. 10. 31.
윈도우 소켓 ] 소켓과 연결된 원격 호스트의 IP주소와 Port번호 가져오기, getpeername() getpeername() int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); sockfd: 정보를 얻고자 하는 소켓의 파일 디스크립터 addr: 원격 호스트 주소 정보를 저장할 sockaddr 구조체 포인터. 주로 struct sockaddr_in 변수를 만들고 (struct sockaddr*)로 캐스팅하여 사용함 addrlen: 구조체의 크기를 나타내는 변수 주소, sizeof 연산자 사용 사용 예시. struct sockaddr_in serverAddr; socklen_t addrLen = sizeof(serverAddr); // 연결된 원격 호스트 정보 얻기 if (getpeername(sockfd, (struct sock.. 2023. 10. 28.
Win32 API ] waitForSingleObject, waitForMultipleObjects waitForSingleObject() 이 함수는 다양한 유형의 핸들에 대한 대기 및 감시를 지원한다. 핸들이 신호를 보낼 때까지 또는 타임아웃이 발생할 때까지 블록되며, 해당 이벤트가 발생하면 반환된다. DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ); hHandle: 대기하려는 핸들(이벤트, 뮤텍스, 세마포어 등) dwMilliseconds: 밀리초 단위 대기 제한 시간, 0을 사용하면 바로 반환하고 INFINITE를 사용하면 무한 대기한다. DWORD 리턴값 WAIT_OBJECT_0(0): 대기가 성공적으로 종료된 경우. 대상 핸들이 스레드인 경우엔 스레드가 종료된경우, 대상 핸들이 뮤텍스인 경우엔 뮤텍스 락을 획득한 경우, 대상.. 2023. 10. 14.
고해상도 타이머 QueryPerformanceFrequency, QueryPerformanceCounter 윈도우 운영체제에서 시스템의 경과 시간을 측정하는 데 사용되는 함수로 GetTickCount()와 GetTickCount64()가 있다. 이 함수는 시스템 부팅 이후 경과한 밀리초(ms)단위의 시간을 반환하며 주로 시간 간격을 측정하는 데 사용된다. GetTickCount() 함수는 32비트 부호없는 정수 타입으로 시간을 반환하며, 시스템이 부팅된 이후 49.7일이 지나면 오버플로우가 발생되므로 64비트 부호없는 정수로 시간을 반환하는 GetTickCount64()를 대신 사용하는 것이 권장된다. 다만 이 함수의 해상도는 일반적으로 10밀리초에서 16밀리초 범위의 시스템 타이머의 해상도로 제한되기 때문에, 조금더 고해상도 타이머가 필요하다면 QueryPerformanceFrequency(), QueryP.. 2023. 10. 9.
윈도우 소켓 ] 논블로킹 소켓, ioctlsocket, 소켓 함수의 리턴 조건과 WSAEWOULDBLOCK이 리턴되는 상황 socket() 함수로 생성된 소켓은 기본적으로 블로킹 소켓이다. 그리고 블로킹 소켓은 소켓함수 호출 시 조건을 만족할 때까지 리턴하지 않는다. 주요 소켓 함수별 리턴 조건은 다음과 같다. accpet() : 접속한 클라이언트가 있을때 connect() : 서버에 접속 성공했을 때 send() : 응용 프로그램이 전송 요청한 데이터를 소켓 송신 버퍼에 모두 복사했을 때 recv() : 소켓 수신 버퍼에 도착한 데이터를 응용 프로그램이 제공한 버퍼에 복사했을 때 반면 논블로킹 소켓은 소켓함수 호출 시 조건을 만족하지 않아도 함수가 리턴하고 다음 코드가 수행된다. socket()으로 생성된 소켓을 논블로킹 소켓으로 소켓 모드를 변경하는 방법은 다음과 같다. u_long on = 1; if (ioctlsock.. 2023. 10. 2.
윈도우 소켓 ] 소켓 옵션, setsockopt, getsockopt, SOL_SOCKET 옵션들 setsockopt setsockopt 함수는 소켓 옵션을 설정하는 데 사용된다. int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); sockfd : 옵션을 설정할 대상이 되는 소켓을 식별하는 데 사용되는 소켓 디스크립터로, 소켓을 생성하고 열 때 반환되는 정수값이다. level: 설정하려는 옵션이 어느 레벨에 속하는지 지정한다. 주로 SOL_SOCKET 레벨을 사용하고, 특정 프로토콜 레벨 옵션인 경우, IPPROTO_IP, IPPROTO_IPV6, IPPROTO_TCP 등을 사용할 수 있다. optname: 설정하려는 옵션의 이름을 지정한다. 예를 들어, SO_BROADCAST, SO_KEEP.. 2023. 10. 1.
윈도우 소켓 ] connect 비동기로 처리하기 논블로킹 소켓으로 설정한 뒤 connect를 시도한다. connect 함수의 리턴값이 SOCKET_ERROR인 경우, WSAGetLastError()로 오류를 확인하여 WSAEWOULDBLOCK 인 경우 현재 백그라운드에서 연결이 진행중임을 나타낸다. writeSet에 소켓을 넣고 select 함수를 호출하여 타임아웃 시간 동안 write-ready 상태가 되는지 감지한다. select() 함수는 오류가 발생한 경우 -1, 타임아웃인 경우 0 그리고 이벤트를 감지한 경우 감지한 소켓 수를 리턴한다. // 논블로킹 모드로 설정 u_long nonBlockOpt = 1; if (ioctlsocket(cSocket, FIONBIO, &nonBlockOpt) == SOCKET_ERROR) { OutputDebu.. 2023. 9. 30.
C] strstr 함수 구현 strstr() 함수는 substring을 찾는 함수로 str1에서 str2를 찾는다. str2의 길이가 0이면 str1을 리턴, str2를 못찾으면 NULL을 리턴, str2를 찾았으면 str1에서 str2 시작 위치의 포인터를 리턴한다. const char* my_strstr(const char* str1, const char* str2) { char* ret; int found = 0; if (*str2 == 0) { ret = str1; } else { for(; *str1 != 0; str1++) { if(*str1 == *str2) { const char *s1 = str1; const char *s2 = str2; while(*s1 == *s2 && *s2 != 0) { s1++; s2++;.. 2023. 9. 15.
C ] Data Types Range C type stdint.h type Bits Sign Range char uint8_t 8 Unsigned 0 .. 255 signed char int8_t 8 Signed -128 .. 127 unsigned short uint16_t 16 Unsigned 0 .. 65,535 short int16_t 16 Signed -32,768 .. 32,767 unsigned int uint32_t 32 Unsigned 0 .. 4,294,967,295 int int32_t 32 Signed -2,147,483,648 .. 2,147,483,647 unsigned long long uint64_t 64 Unsigned 0 .. 18,446,744,073,709,551,615 long long int64_t 6.. 2023. 9. 15.
extern "C" {} extern "C" {} 는 .cpp 소스파일에서 C 스타일로 작성된 함수나 변수를 사용하기 위한 C++의 키워드로, extern "C" {} 문구를 사용하면 해당 블록 내에 있는 함수나 변수를 C 스타일로 링크하도록 지시할 수 있다. C++ 컴파일러는 C++ 언어의 특징을 따르는데, C++은 함수 오버로딩, 이름 맹글링(name mangling) 등의 기능을 지원하기 때문에 C 와는 다른 링킹 규칙을 가지고 있다. 따라서 extern "C" 키워드를 사용하면 C++ 코드에서 해당 블록 내에 선언된 C 함수나 C 변수를 호출 또는 참조할 때 C 스타일의 링킹 규칙을 따르도록 한다. extern "C" { // C 함수 extern void myCFunction(int arg); } extern "C" {.. 2023. 7. 18.
C, C++ ] system("pause") 대신 사용할 수 있는 방법 system("pause")는 운영체제에 종속적이고 운영체제에게 "pause"라는 명령을 실행하도록 요청하므로 비슷한 기능을 구현할 다른 방법을 생각해보자. C 윈도우 환경에서만 가능한 방법 #include #include int main() { printf("Press any key to continue...\n"); while (!_kbhit()); (void)_getch(); return 0; } conio.h 는 윈도우에서만 사용 가능하다. C #include int main() { printf("Press Enter to continue...\n"); (void) getchar(); return 0; } getchar()는 표준 라이브러리이기 때문에 이식성이 좋으며, 보다 간단하게 사용자의 입력.. 2023. 7. 11.
C ] 포인터와 const const는 변수나 함수 매개변수를 선언할 때 사용되는 한정자로 값을 변경할 수 없음을 나타낸다. 변수를 상수로 취급하고자 할 때 유용하며, 많은 곳에서 참조되고 변경되는 것을 원하지 않는 정적인 정보를 보호하는데 사용된다.  포인터 형식과 const 한정자가 같이 쓰일 때 const의 위치에 따라 다음과 같은 차이가 있다.   1. 상수를 가리키는 포인터 : ptr의 역참조를 통해 값을 변경할 수 없지만, ptr이 다른 주소를 가리키도록 변경할 수 있다.const int* ptr     2. 상수 포인터 : ptr 자체를 다른 주소를 가리키도록 변경할 수 없지만, ptr의 역참조를 통해 값을 변경할 수 있다.int* const ptr     3. 상수를 가리키는 상수 포인터 : ptr이 가진 주소를 변.. 2023. 5. 30.
C ] 비트필드와 공용체 사용 #include #include typedef struct { uint32_t bit1 : 1; uint32_t bit2 : 2; uint32_t bit3 : 3; } MyBits; union MyUnion { uint32_t all; MyBits bits; }; int main() { union MyUnion myUnion; myUnion.all = 0; myUnion.bits.bit1 = 1; myUnion.bits.bit2 = 2; myUnion.bits.bit3 = 5; printf("all: %u\n", myUnion.all); printf("bit1: %u\n", myUnion.bits.bit1); printf("bit2: %u\n", myUnion.bits.bit2); printf("bit3.. 2023. 5. 29.
C언어 ] setjmp(), longjmp() setjmp()와 longjmp()함수를 사용하기 위해서는 먼저 setjmp.h를 포함해야한다. #include 쉽게 생각하면 setjmp()는 시스템 복원 지점을 만들고, longjmp()는 시스템 복원을 하는 것과 같다. setjmp() int setjmp(jmp_buf env); setjmp() 함수는 현재의 위치(스택 환경)을 저장하고, 나중에 longjmp() 함수를 호출되었을 때 그 위치로 다시 돌아가는 데 사용된다. longjmp() void longjmp(jmp_buf env, int val); longjmp() 함수는 setjmp() 함수를 통해 저장된 위치로(스택환경으로) 프로그램 실행을 이동(복원)하는 데 사용된다. longjmp() 함수가 호출되면 setjmp() 함수 호출 이후에 .. 2023. 5. 7.
C언어 ] 맵 자료구조 구현 map 생성시 사이즈를 직접 결정할 수 있도록 해보았다. 근데 링버퍼처럼 범용적으로 쓸 거 같진 않아서 사실 고정길이배열로 mapManger 구조체안에 둬도 될 것 같다. map.h #include "main.h" #define MAP_MAX_KEY_LEN20 // 맵 자료구조 typedef struct { char key[MAP_MAX_KEY_LEN+1]; uint32_t value; } map_t; // 맵 자료구조 관리 구조체 typedef struct { map_t* maps; uint32_t currentSize; uint32_t maxSize; } mapManager_t; void map_create(mapManager_t* mapManager, map_t* maps, uint32_t maxS.. 2023. 5. 7.
C ] float to hex / hex to float Converter 2023.04.09 - [프로그래밍/C# (WinForms)] - C#, WinForms ] float to hex / hex to float Converter C#, WinForms ] float to hex / hex to float Converter 필요에 의해서 만들었다. 내가 예전에 소개한 float to hex converter 사이트랑 달리 시스템 아키텍쳐에 따라 메모리에 저장된 대로 보여준다. 디자이너 부분을 먼저 살펴보면 Form은 사용자가 크기를 eteo.tistory.com 위 글에서 WinForms로 만든 float to hex / hex to float Converter를 C언어로 간단히 구현해 본 것. 예외처리나 옵션 없이 리틀엔디안으로 변환하는 기능만 넣었다. #include .. 2023. 4. 9.
C ] 시간복잡도가 O(1)인 2의 거듭제곱 판별 int isPowerOfTwo(int n) { return (n && ((n & (n - 1)) == 0)); } 2의 거듭제곱은 가장 왼쪽에 있는 1을 제외하고 뒷부분이 전부 0이라는 걸 고려할 때 위와 같은 코드로 판별할 수 있다. 그리고 어떤 정수를 2의 거듭제곱 수로 나눈 나머지 연산을 해야할 때 성능향상을 위한 최적화 기법으로 %연산이 아니라 &연산을 쓰기도 한다. 위와 같은 논리이다. #define SOME_NUMBER_POWER_OF_TWO8 int getRemainder(int n) { return n & (SOME_NUMBER_POWER_OF_TWO - 1); } 2023. 3. 31.