Побайтное считывание памяти: «подписанный символ *» против «беззнаковый символ *» - PullRequest
16 голосов
/ 05 декабря 2011

Часто нужно читать из памяти по одному байту за раз, как в этой наивной memcpy() реализации:

void *memcpy(void *dest, const void *src, size_t n)
{
    char *from = (char *)src;
    char *to   = (char *)dest;

    while(n--) *to++ = *from++;

    return dest;
}

Однако иногда я вижу, как люди явно используют unsigned char * вместо char *.

Конечно, char и unsigned char могут быть не равны.Но имеет ли значение, использую ли я char *, signed char * или unsigned char * при побитном чтении / записи памяти?

ОБНОВЛЕНИЕ: На самом деле, я полностью осознаю, чтоc=200 может иметь разные значения в зависимости от типа c.Здесь я спрашиваю, почему люди иногда используют unsigned char * вместо просто char * при чтении памяти, например, для хранения uint32_t в char[4].

Ответы [ 5 ]

21 голосов
/ 05 декабря 2011

Вы должны использовать unsigned char.Стандарт C99 гласит, что unsigned char является единственным типом, который гарантированно является плотным (без битов заполнения), а также определяет, что вы можете копировать любой объект (кроме битовых полей) точно, копируя его в массив unsigned char, который является представление объекта в байтах.

Разумная интерпретация этого для меня заключается в том, что если вы используете указатель для доступа к объекту в виде байтов, вы должны использовать unsigned char.

Ссылка: http://blackshell.com/~msmud/cstd.html#6.2.6.1C1x осадка C99)

12 голосов
/ 05 декабря 2011

Это одна точка, в которой C ++ отличается от C. Вообще говоря, C гарантирует только доступ к необработанной памяти для unsigned char;char может быть подписано, и на 1-й машине дополнения или знаковой величины значение -0 может быть автоматически преобразовано в +0, изменяя битовую комбинацию.По какой-то причине (неизвестно мне) комитет C ++ расширяет гарантии, поддерживающие прозрачное копирование (без изменений в битовых шаблонах), до char, а также unsigned char;на приборе со знаком 1 или величиной со знаком у разработчиков нет иного выбора, кроме как сделать простой знак char без знака, чтобы избежать таких побочных эффектов.(И, конечно же, большинство программистов сегодня не заботятся о таких машинах)или машина со знаком) будет автоматически использовать unsigned char.Также часто принято резервировать обычные char для символьных данных уникально, с signed char для очень маленьких целочисленных значений и unsigned char для необработанной памяти или когда предполагается битовая манипуляция.Такое правило позволяет читателю различать различные варианты использования (при условии, что оно строго соблюдается).

2 голосов
/ 05 декабря 2011

В вашем примере кода это не имеет значения.Но если вы хотите отобразить / распечатать значение байта, чем оно делает (поскольку старший бит интерпретируется по-разному), и unsigned char кажется более подходящим

0 голосов
/ 05 декабря 2011
#include<stdio.h>
#include<string.h>

int main()
{

unsigned char a[4]={254,254,254,'\0'};
unsigned char b[4];
char c[4];

memset(b,0,4);
memset(c,0,4);

memcpy(b,a,4);
memcpy(c,a,4);
int i;
for(i=0;i<4;i++)
{
    printf("\noriginal is %d",a[i]);
    printf("\nchar %d is %d",i,c[i]);
    printf("\nunsigned char %d is %d \n\n",i,b[i]);
}

}

вывод

original is 254
char 0 is -2           
unsigned char 0 is 254 


original is 254
char 1 is -2
unsigned char 1 is 254 


original is 254
char 2 is -2
unsigned char 2 is 254 


original is 0
char 3 is 0
unsigned char 3 is 0 

поэтому здесь char и unsign имеют одинаковое значение, поэтому в данном случае это не имеет значения

Редактировать

если вы прочитаете что-либо как знаковый символ, все равно в этом случае самый старший бит также будет скопирован, поэтому это не имеет значения

0 голосов
/ 05 декабря 2011

Это зависит от того, что вы хотите хранить в символе. Символ со знаком дает диапазон от -127 до 127, а знак без знака - от 0 до 255.

Для арифметики указателей это не имеет значения.

...