char * vs unsigned char * в чем разница? - PullRequest
0 голосов
/ 18 июня 2020

В Linux с c я не понял, в чем разница между char* и unsigned char* Когда я читаю / записываю двоичный буфер?

Когда я не должен использовать char* и нужно использовать unsigned char*?

1 Ответ

2 голосов
/ 18 июня 2020

Первый отзыв C имеет unsigned char, signed char и char: 3 различных типа. char имеет тот же диапазон, что и unsigned char или signed char.

[Edit]

OP добавлен «Когда я читаю / записываю двоичный буфер», поэтому разделы, расположенные ниже (мои исходный пост) посвящен тому, "в чем разница между char* и unsigned char*" с примером случая без этой проблемы r / w. В этом разделе ....

Чтение / запись двоичного файла через <stdio.h> может быть выполнено с помощью любой функции ввода-вывода, хотя чаще используется fread()/fwite().

Для байта ориентированных данных, все функции ввода / вывода ведут себя так, как если бы

Функции байтового ввода считывают символы из потока, как если бы они выполнялись последовательными вызовами функции fgetc. C17dr § 7.21.3 11 Функции вывода байтов записывают символы в поток, как если бы они были последовательными вызовами функции fputc. § 7.21.3 12

Итак, давайте посмотрим на эти два.

... функция fgetc получает этот символ как unsigned char ... § 7.21.7.1 2 Функция fputc записывает символ, указанный в c (преобразованный в unsigned char) § 7.21.7.3 2

Таким образом, все операции ввода-вывода на самом низком уровне лучше всего рассматривать как чтение / writing unsigned char.

Теперь, чтобы напрямую обращаться к

Когда я не должен использовать char* и должен использовать unsigned char*? (OP)

При записи указатели, такие как char*, unsigned char* или другие, могут использоваться в коде уровня OP, но основная функция вывода обращается к данным через unsigned char *. Это не влияет на выполнение OP записи, кроме случаев, когда char был закодирован как величина дополнения / знака единицы - код прерывания не будет обнаружен.

Аналогично с чтением, базовая функция ввода сохраняет данные через unsigned char *, и ловушек не происходит. При чтении одного байта через int fgetc() будут представлены значения в диапазоне unsigned char, даже если char равно со знаком .

Важность использования unsigned char* по сравнению с char* в чтение / запись двоичного буфера происходит не столько в самом вызове ввода / вывода (все это unsigned char * доступ), сколько в настройке данных перед записью и интерпретации данных после чтения - см. memcmp() ниже.

Когда я не должен использовать char* и должен использовать unsigned char*?

Хороший пример - код, связанный со строкой.

Хотя функции в <string.h> использовать char* в параметрах функции, реализация выполняется так, как если бы char было unsigned char, даже если char равно подписано .

Для всех функций в В этом подпункте каждый символ должен интерпретироваться так, как если бы он имел тип unsigned char (и поэтому каждое возможное представление объекта является допустимым и имеет другое значение). C17dr § 7.24.1 3

Таким образом, даже если char является подписанным char, такие функции, как int strcmp(char *a, char *b), выполняются так, как если бы int strcmp(unsigned char *a, unsigned char *b).

  1. Это имеет значение, когда строка отличается подписью char c и char d со значениями разных знаков. Например, предположим, что c < 0, d > 0

    // Доступ через char * и char подписан c unsigned char * c> d is false

Это приводит к знаку, отличному от знака strcmp(), что влияет на сортировку строк.

// Incorrect code when `char` is signed.
int strcmp(const char *a, const char *b) {
  while (*a == *b && *a) { a++; b++; }
  return (*a > *b) - (*a < *b);
}

// Correct code when `char` is signed or unsigned, 2's complement or not
int strcmp(const char *a, const char *b) {
  const char *ua = a;
  const char *ub = b;
  while (*ua == *ub && *ua) { ua++; ub++; }
  return (*ua > *ub) - (*ua < *ub);
}

[Edit]

То же самое относится и к двоичным данные прочитаны и сравнены с memcmp().

В старых реализациях C, в которых не использовалось дополнение 2, могло быть 2 нуля: +0 и -0 (или ловушка).

+ 0 заканчивал строку при правильном просмотре как а unsigned char. -0 не является нулевым символом для завершения строки, хотя как подписанный char он имеет нулевое значение.

// Incorrect code when `char` is signed and not 2's complement.
// Conversion to `unsigned char` done too late.
int strcmp(const char *a, const char *b) {
  while ((unsigned char)*a == (unsigned char)*b && (unsigned char)*a) { a++; b++; }
  return ((unsigned char)*a > (unsigned char)*b) - ((unsigned char)*a < (unsigned char)*b);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...