"void 포인터 연산은 호환성을 위해 사용하지 않는 것이 좋습니다. 즉, 표준을 지켜야 호환성이 좋은 코드가 됩니다. 만약 메모리를 1바이트씩 접근하려면 unsigned char *를 사용하면 됩니다."
https://dojang.io/mod/page/view.php?id=790
라고 하셨는데 왜 unsigned char 포인터를 써야하나요?
char포인터를 쓰면 안되는 이유가 있나요?
애초에 unsigned char 포인터와 char 포인터에 차이점이 있나요?
둘다 1바이트씩 접근 하지 않나요?
0 to 255 (unsigned) by default. -128 to 127 (signed) when compiled with |
unsigned int x = 0xFFFFFFFF;
int *y = (int *)&x;
printf("%d\n", y);
답변 정말 감사합니다.
질문을 조금 더 구체적으로 드려도 괜찮을까요?
메모리 관련 함수 구현예시를 보면 void 포인터를 unsigned char 포인터로 캐스팅해서
https://clc-wiki.net/wiki/C_standard_library:string.h:memset
Implementation
In standard C, this can be implemented as:
#include <stddef.h> /* size_t */ void *memset(void *s, int c, size_t n) { unsigned char* p=s; while(n--) *p++ = (unsigned char)c; return s; }
이런식으로 구현이 되어있습니다. 다른 사이트에서도 void포인터를 char포인터가 아닌 unsigned char 포인터로 캐스팅해서 구현하고 있습니다.
다른 해외 포럼에서는 메모리 관련 함수를 구현할 때 void 포인터를 unsigned char 포인터로 캐스팅해서 사용하라고는 하는데 그 이유에 대해서는 언급하지 않더라고요.
예를 들어 main 함수의 int 배열의 포인터를 memset구현함수 매개변수인 void 포인터로 받고 그것을 char 포인터로 캐스팅하더라도 문제가 없는데 말이죠.
unsigned char 포인터나 char 포인터나 결국 8비트, 즉 1바이트씩 끊어서 메모리에 접근하기 때문에 둘 중 무엇을 써도 상관이 없을 거 같은데 굳이 unsigned char만 써야하는 이유가 궁금합니다.
다른 사이트에서는 memset구현시 두번째 매개변수 int c를 unsigned char로 캐스팅해서 사용해야하기 때문에 void 포인터를 unsigned char로 캐스팅해서 unsigned라는 이름을 맞춰줘야 한다고 하는데, char 포인터를 사용해도 똑같은 역할을 한다고 생각합니다.
부호가 있는 값이나 없는 값이나 무엇을 대입하든 결국 unsigned char 포인터나 char 포인터 둘 다 8비트, 즉 1바이트씩 끊어서 접근하는 역할만 하니까요.
결론적으로 드리고 싶은 질문은 memset 함수 구현시 void 포인터를 unsigned char 포인터로 캐스팅해서 사용해야만 하는 이유가 있나요?
이미 답변했지만,
메모리 주소에 부호 있는 정수 타입을 쓰면 안 됩니다.
올바르게 동작하지 않는다, 프로그램이 중단되는 예시 코드도 넣었습니다.
비부호 정수로 처리해야 한다. 관례다.
부호 정수로 처리하면 처리과정에서 오동작을 일으키고 프로그램이 죽는다. 툭하면 죽는 프로그램을 작성하고 싶다면 쓰시면 된다. 다른 프로그래밍 언어는 아예 금지한다.
됐죠?
그러면 왜 관례가 unsigned를 쓰는 것이냐? C 언어 역사가 그렇고, 표준이 그렇다. 심지어 char의 부호도 표준에서 정해지지 않았다. ARM에서는 char라고 쓰면 디폴트가 unsigned char이다.
이렇습니다.
void 포인터로 연산하면 안 됩니다.
10000000 >> 1 = 01000000 (128 / 2 = 64)
10000000 >> 1 = 11000000 (-128 / 2 = -64)