Во-первых, я прошу прощения за любые ошибки на английском, которые я сделаю, но быть 15 и французский не помогает …
Я пытаюсь запрограммировать декодер PNG с помощью спецификации формата файла (http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html) но я столкнулся со странной проблемой.
В спецификации говорится, что первые восемь байтов файла PNG всегда содержат следующие (десятичные) значения: 137 80 78 71 13 10 26 10.
Когда я тестирую эту простую программу:
int main()
{
ifstream file("test.png");
string line;
getline(file, line);
cout << line[0] << endl;
}
Выход «ë», который представляет 137 в таблице ascii. Хорошо, это соответствует первому байту.
Тем не менее, когда я делаю int ascii_value = line[0];
выходное значение равно -119, что не является правильным значением ASCII.
Когда я пытаюсь сделать то же самое с другим символом, таким как «e», он выводит правильное значение ascii.
Может кто-нибудь объяснить, что я делаю не так и каково решение? Я лично думаю, что это проблема с расширенной таблицей ASCII, но я не уверен.
Спасибо всем ! Я брошу свой подписанный символ на неподписанный !
Ваша система char
Тип подписан, поэтому его значения могут быть отрицательными.
Вы должны быть явными и опустить знак:
const unsigned char value = (unsigned char) line[0];
Обратите внимание, что -119 = 137 в дополнение двух который использует ваша машина. Так что сами биты действительно верны, все дело в их правильной интерпретации.
char
в C ++ может быть как подписанным, так и неподписанным1), это до реализации, которая это. В случае вашего компилятора (как в большинстве случаев, на самом деле) он, кажется, подписан:
Любое символьное значение> 128 представляется как отрицательное число. -119 соответствует неподписанный значение символа 137. Другими словами, имеет место следующее:
unsigned char c = 137;
assert(static_cast<signed char>(c) == -119);
Но обратите внимание, что это зависит от реализации, поэтому вы не можете в целом полагаться на эти значения.
1) И является отличный тип от обоих signed char
а также unsigned char
,
ASCII охватывает только 0 .. 127. В таблице ASCII нет 137.
Также нет такой вещи как «расширенная таблица ASCII». Существуют десятки (взаимно несовместимых) расширений ASCII. Черт, технически даже Unicode — это «расширенный ASCII».
Вы получаете -119, потому что в вашем компиляторе char
тип со знаком, охватывающий значения от -128 до 127. (-119 — 137 — 256). Вы можете получить ожидаемое значение, явно приведя к unsigned char
:
int value = static_cast<unsigned char>(line[0]);
Вот что происходит, когда вы разрешаете расширение знака. Символы в расширенной таблице ASCII имеют свой старший бит (знаковый бит).
-119 это 0x89
, 137 также 0x89
,
Пытаться
int ascii_value = line[0] & 0x00FF;
или же
int ascii_value = (unsigned char)line[0];
137 = -119 = 0х89. Если вы бросили (unsigned) (unsigned char)(line[0])
, вы получите его, чтобы напечатать целое значение 137.
Тип char
(который является базовым типом для std::string
) [обычно] значение со знаком, в диапазоне от -128-127. Все, что выше 127, будет отрицательным числом.
C ++ не указывает, является ли char
является подписанным или неподписанным типом. Это означает, что «расширенные» символы ASCII (те, которые находятся вне диапазона 0..127 с установленным верхним битом) могут интерпретироваться как отрицательные значения; и похоже, что это то, что делает ваш компилятор.
Чтобы получить ожидаемое значение без знака, вам нужно явно преобразовать его в unsigned char
тип:
int ascii_value = static_cast<unsigned char>(line[0]); // Should be 137