Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.207.133.13] |
|
Сообщ.
#1
,
|
|
|
Добрый день!
Занимаюсь целочисленным программированием и по этой причине часто использую целые типы данных. С основными целочисленными типами данных работается легко и без проблем: short, int, long long int... (и соответствующие unsigned). Но вот есть в C/C++ загадочный целочисленный тип данных: char С ним-то и возникают проблемы. При попытке его использования (работа с целыми числами от -128 до 127) все программы работают правильно, но компиляторы (особенно современные) выдают просто россыпь предупреждений: warning: array subscript has type ‘char’ [-Wchar-subscripts] Например, в небольшой программе решения Задачи Коммивояжера методом динамического программирования мне выдается 52 (!!!) предупреждения! Как я понял, проблема довольно фундаментальная. Даже при чтении/выводе на консоль целых переменных типа char не существует специального модификатора. Приходится с printf/scanf использовать %hhd. И тоже с предупреждениями. Вопрос: какой прием надо использовать для целочисленных переменных типа char, чтобы избавиться от этих бесконечных предупреждений? Может ключ какой-то надо указать компилятору? P.S. 1. Зачем все это? Просто переменная типа char занимает 1 байт, а уже переменная типа short - аж 2 байта. Для некоторых задач целочисленного программирования эта экономия существенна! (В Паскале все было проще - там byte и char разные типы данных). 2. Все те же вопросы актуальны и для типа unsigned char. 3. Наверное, этой теме уже лет 60 - ровно столько, сколько существует язык Си. И она давно уже разжевана. Тогда просьба - дайте ссылку на статью, где все это объясняется покороче и "на пальцах". |
Сообщ.
#2
,
|
|
|
char это символ, и, более того, его знаковость это то ли implementation defined, то ли unspecified behavior. Если тебе нужны однобайтовые целые, то используй явно signed/unsigned char, с ними не должно проблем возникать.
Добавлено Цитата mkudritsky @ (В Паскале все было проще - там byte и char разные типы данных). Формально в плюсах тоже - std::is_same_of_v<char, (un)signed char> всегда false вне зависимости от знаковости char. И на cppreference вот что пишут: Цитата char - type for character representation which can be most efficiently processed on the target system (has the same representation and alignment as either signed char or unsigned char, but is always a distinct type). |
Сообщ.
#3
,
|
|
|
Тип char это именно код узкого символа. И поток ostream понимает его именно как символ, а не число. Аналогично с другими функциями.
Кроме типа "char", есть ещё два типа "signed char" и "unsigned char". Это три разных типа! Впрочем, они тоже отчасти несут смысл кода символа. Знаковость типа "char", не определена. К примеру в компиляторе microsoft c++, её можно изменить параметром компилятора. Так что char годится только для кодирования ascii. Хранить же маленькое число можно в char. Если размерность устраивает, то почему бы не использовать. В этом плане предупреждений нет и не должно быть. Чтобы вывести числовое значение char, использую приведение к int. В итоге компилятор понимает, что это число и перестаёт ворчать. Это именно для вывода. Другое место, где могут возникнуть предупреждения, это сужения типов. При неявном приведении из большого числа к меньшему, компилятор будет ворчать. В таких случаях использую явное приведение static_cast. |
Сообщ.
#4
,
|
|
|
Всем спасибо за помощь!
Действительно, замена char на signed char привела к отмене множества предупреждений! И вообще теперь буду внимательнее работать с этими типами данных. Раньше я вообще думал, что слово "signed" в C/C++ добавлено "для красоты" и его всегда можно опустить. Как видим, не всегда. Это служебное слово учит программиста аккуратности. |
Сообщ.
#5
,
|
|
|
Цитата mkudritsky @ я вообще думал, что слово "signed" в C/C++ добавлено "для красоты" и его всегда можно опустить. Как видим, не всегда. Для типа char signed действительно имеет значение. В других случаях его действительно можно опустить. Типы: "int", "signed" и "signed int" являются одним и тем же типом. |
Сообщ.
#6
,
|
|
|
Откройте для себя удивительный мир stdint.h и навсегда забудьте о всех signed/unsigned char, int, long, long long. В хорошо написанной программе должны быть только типы из stdint.h и char (для хранения символов).
|
Сообщ.
#7
,
|
|
|
Цитата Dushevny @ Откройте для себя удивительный мир stdint.h и навсегда забудьте о всех signed/unsigned char, int, long, long long. В хорошо написанной программе должны быть только типы из stdint.h и char (для хранения символов). В принципе верно с оговорками. Про базовую целочисленную арифметику соглашусь и поддержу. Я подключаю cstdint, типы которого использую. Но принципы надо понимать. Всякие signed и unsigned это основы языка. Даже если они не используются в обычных случаях, то всё равно влияют. А на счёт символов тут спорно. В разных случаях использую char, wchar_t и даже char32_t. Одного char категорически мало. |
Сообщ.
#8
,
|
|
|
Как раз для того, чтобы убрать неоднозначность, то ли малое целое, то ли символ, фикъегознает, что тут программист имел в виду, в Плюсах char сделали отдельным типом. Вам нужен символ – используйте char, нужно малое целое, добавьте к нему указание знаковости. Это здорово помогает в чтении исходников, ну а компилятор пытается в этом помогать.
Добавлено P.S. Модификатор hh для типов вполне Стандартен, начиная с C99 и C++11. Можно пользоваться без ограничений. |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ Вам нужен символ – используйте char, нужно малое целое используйте (u)int_fast8_t, нужно экономить байты в памяти - используйте (u)int_least8_t, нужно описать байт, передающийся в составе пакета с прибитым гвоздями форматом - используйте uint8_t. И никаких (un)signed char/int/long и т.п. Компилятор сам подставит наиболее подходящий тип. "По-моему так!". "Машина должна работать, а человек - думать" Цитата Eric-S @ Согласен. А на счёт символов тут спорно. В разных случаях использую char, wchar_t и даже char32_t. Одного char категорически мало. |
Сообщ.
#10
,
|
|
|
Немного поясню, к чему я стремлюсь.
Сейчас принудительно пишу часть программ на классическом Си. Ну просто сам для себя решил, что надо поглубже освоить этот замечательный язык. И писать часть сложных программ без использования классов С++. Ну а библиотека stdint.h, наверное, есть расширение классического синтаксиса Си (?). Пока в расширения классики не лезу. Хотя и С++ очень нравится, особенно вектора, множества, итераторы, алгоритмы... И все такое быстрое - не медленнее классического Си. Цитата Qraizer @ Модификатор hh для типов вполне Все равно %hhd отказывается без ругани и предупреждений читать signed char. Пока примерно так действую: short Nzk; // Число городов, которые должен обойти коммивояжер signed char Ng; // Число городов // Задание числа городов printf("Число городов Nzk = "); if (!scanf("%hd", &Nzk)) { printf("Не могу прочитать число городов Nzk\n"); return -1; } Ng = (signed char)Nzk; // Тут в реальной программе проверка, чтобы -129 < Nzk < 128 Не знаю, мне почему-то дискомфортно, когда компилятор на ровном месте выдает предупреждения. Стараюсь этого избегать, по крайней мере в таких тривиальных участках кода. |
Сообщ.
#11
,
|
|
|
Цитата mkudritsky @ для этого нам свыше дан inttypes.h Все равно %hhd отказывается без ругани и предупреждений читать signed char. |
Сообщ.
#12
,
|
|
|
Цитата mkudritsky @ Ну если брать реализацию, которая не поддерживает C99 (а таких хватает), то эффект будет печальным. Смотри документацию на свои средства разработки. Все равно %hhd отказывается без ругани и предупреждений читать signed char. |