buffer = realloc(buffer, sizeof(uint32_t));
sprintf(buffer, "%d", gid);
offset += sizeof(uint32_t);
buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
sprintf(buffer+sizeof(uint32_t), "%d", uid);
: 예를 들어.
보통 CHAR_BIT == 8
이라고 가정하면, sizeof(uint32_t) == 4
입니다. 또한 int
은 패딩 비트가없는 2의 보수 표현으로 부호있는 32 비트 정수라고 가정합시다.
sprintf(buffer, "%d", gid)
은 gid
의 비트 패턴 표현을 버퍼에 int
으로 해석하여 인쇄합니다. 위의 가정하에 gid
은 -2147483648과 2147483647 사이의 숫자로 해석됩니다. 따라서 십진수 문자열 표현은 '-'
을 포함 할 수 있으며 1에서 10 자리 숫자와 0 종결자를 포함하며 모두 2에서 12 바이트를 사용합니다. 그러나 4 바이트 만 할당 했으므로 999 < gid < 2^32-99
(부호가있는 2의 보수가 > 999
또는 < -99
) 인 경우 sprintf
은 할당 된 버퍼 크기를 초과하여 씁니다.
이것은 정의되지 않은 동작입니다.
일반적으로 4 바이트를 할당하면 메모리가 더 효율적으로 사용되므로 (예 : malloc
이 16 바이트로 정렬 된 블록을 반환하는 경우 할당 된 4 바이트 바로 뒤에 12 바이트를 다른 부분에서 사용할 수 없음) 프로그램이지만 프로그램의 주소 공간에 속하며, 아마도 그들에게 글쓰기는 감지되지 않을 것입니다).그러나 할당 된 청크의 끝이 페이지 경계에있을 때 쉽게 추락 할 수 있습니다.
sprintf
s에 대해 쓰기 오프셋을 4 바이트 씩 늘리므로 문자열 표현 (0-termnator 제외)이 4 바이트 이상을 사용하면 이전 숫자의 일부가 덮어 쓰여집니다 (프로그램이 아직 할당되지 않은 메모리에 쓰기 때문에 충돌).
라인
buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
는 상기 에러를 포함한다.
buffer = realloc(buffer, new_size);
는 할당 된 메모리에 대한 참조를 잃고 realloc
실패 할 경우 누설을 야기한다. 임시을 사용하여 새로운 할당의 성공
char *temp = realloc(buffer, new_size);
if (temp == NULL) {
/* reallocation failed, recover or cleanup */
free(buffer);
exit(EXIT_FAILURE);
}
/* it worked */
buffer = temp;
/* temp = NULL; or let temp go out of scope */
새로운 크기 sizeof(uint32_t) + sizeof(buffer)
를 확인하는 것은 항상 sizeof(uint32_t) + sizeof(char*)
동일합니다. 일반적으로 8 바이트 또는 12 바이트이므로 할당 된 영역 외부에서 쓰고 크래시 나 메모리 손상 (많은 경우 나중에 크래시가 발생할 수 있음)이 발생하지 않도록 많은 숫자가 필요하지 않습니다.
당신 은buffer
에 할당 된 바이트 수를 추적하고 새 크기를 계산하는 것을 사용해야합니다. 포인터에서 시작까지 할당 된 메모리 블록의 크기를 결정하는 (portable¹) 방법은 없습니다.
이제 문자열 표현 또는 비트 패턴을 버퍼에 저장할지 여부가 문제입니다.
문자열 표현을 저장하면 문자열 표현의 길이가 값에 따라 달라진다는 문제점이 있습니다. 따라서 숫자의 표현 사이에 구분 기호를 포함 시키거나 필요에 따라 모든 표현의 길이를 공백이나 선행 0으로 채워서 동일한 길이를 유지해야합니다. 예를 들어
#include <stdint.h>
#include <inttypes.h>
#define MAKESTR(x) # x
#define STR(x) MAKESTR(x)
/* A uint32_t can use 10 decimal digits, so let each field be 10 chars wide */
#define FIELD_WIDTH 10
uint32_t gid = 1100;
uint32_t uid = 1000;
size_t buf_size = 0, offset = 0;
char *buffer = NULL, *temp = NULL;
buffer = realloc(buffer, FIELD_WIDTH + 1); /* one for the '\0' */
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
buf_size = FIELD_WIDTH + 1;
sprintf(buffer, "%0" STR(FIELD_WIDTH) PRIu32, gid);
offset += FIELD_WIDTH;
temp = realloc(buffer, buf_size + FIELD_WIDTH);
if (temp == NULL) {
free(buffer);
exit(EXIT_FAILURE);
}
buffer = temp;
temp = NULL;
buf_size += FIELD_WIDTH;
sprintf(buffer + offset, "%0" STR(FIELD_WIDTH) PRIu32, uid);
offset += FIELD_WIDTH;
/* more */
uint32_t valorGID;
uint32_t valorUID;
/* rewind for scanning */
offset = 0;
sscanf(buffer + offset, "%" STR(FIELD_WIDTH) SCNu32, &valorGID);
offset += FIELD_WIDTH;
sscanf(buffer + offset, "%" STR(FIELD_WIDTH) SCNu32, &valorUID);
printf("ValorGID %u ValorUID %u \n", valorGID, valorUID);
같이 0으로 채워진 고정 너비 필드가 사용됩니다. 너비가 고정 너비보다 큰 분리 기호를 사용하려면 필요한 길이와 오프셋의 계산이 더 복잡해 지지만 숫자가 크지 않으면 공간을 덜 사용하게됩니다. 당신이 알고있는 경우
size_t buf_size = 0, offset = 0;
unsigned char *buffer = NULL, temp = NULL;
buffer = realloc(buffer, sizeof(uint32_t));
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
buf_size = sizeof(uint32_t);
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
buffer[offset + b] = (gid >> b*8) & 0xFF;
}
offset += sizeof(uint32_t);
temp = realloc(buffer, buf_size + sizeof(uint32_t));
if (temp == NULL) {
free(buffer);
exit(EXIT_FAILURE);
}
buffer = temp;
temp = NULL;
buf_size += sizeof(uint32_t);
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
buffer[offset + b] = (uid >> b*8) & 0xFF;
}
offset += sizeof(uint32_t);
/* And for reading the values */
uint32_t valorGID, valorUID;
/* rewind */
offset = 0;
valorGID = 0;
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
valorGID |= buffer[offset + b] << b*8;
}
offset += sizeof(uint32_t);
valorUID = 0;
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
valorUID |= buffer[offset + b] << b*8;
}
offset += sizeof(uint32_t);
같은 것을 사용하십시오
오히려 저장하는 가장 컴팩트 한 방법이 될 것이다 비트 패턴을 저장하고 싶은 경우는, ¹ 방법 malloc
등 작업 구현시 malloc
의 부기 데이터에서 크기를 찾을 수 있습니다.
귀하의 의견에 진심으로 감사드립니다. 내가 말했듯이, 나는 C.에서 새로운 것이다. 나는 realloc이 실패 하는지를 확인해야한다는 것을 몰랐다. 첫 번째 해결 방법은 문자열 표현입니다. 그것을 구현할 것입니다. 다시 한 번 감사드립니다. – Fdiazreal
반갑습니다. 나는 당신이 chastising하고 있다는 인상을받지 못했기를 바랍니다. 요점은 C에서 프로그래머는 에러 검사를해야한다는 것입니다. 코드의 어떤 부분에서 잘못되었는지 정확히 알려주는 멋진 예외는 없습니다. 물론,'malloc/realloc'의 실패를 검사하는 것은 실패를 결코 감지 할 수없는 좋은 기회입니다. 하지만 한 번만 해내면 기꺼이받을 수 있습니다. –