На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Тип char (unsigned char) как целое число , Как правильно с таким типом работать, чтобы не выдавался ворох предупреждений?
    Добрый день!
    Занимаюсь целочисленным программированием и по этой причине часто использую целые типы данных.

    С основными целочисленными типами данных работается легко и без проблем: short, int, long long int... (и соответствующие unsigned).
    Но вот есть в C/C++ загадочный целочисленный тип данных: char
    С ним-то и возникают проблемы.
    При попытке его использования (работа с целыми числами от -128 до 127) все программы работают правильно, но компиляторы (особенно современные) выдают просто россыпь предупреждений:
    ExpandedWrap disabled
      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 - ровно столько, сколько существует язык Си. И она давно уже разжевана.
    Тогда просьба - дайте ссылку на статью, где все это объясняется покороче и "на пальцах".
    Сообщение отредактировано: mkudritsky -
      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).
        Тип char это именно код узкого символа. И поток ostream понимает его именно как символ, а не число. Аналогично с другими функциями.

        Кроме типа "char", есть ещё два типа "signed char" и "unsigned char". Это три разных типа! Впрочем, они тоже отчасти несут смысл кода символа.

        Знаковость типа "char", не определена. К примеру в компиляторе microsoft c++, её можно изменить параметром компилятора. Так что char годится только для кодирования ascii.

        Хранить же маленькое число можно в char. Если размерность устраивает, то почему бы не использовать. В этом плане предупреждений нет и не должно быть.

        Чтобы вывести числовое значение char, использую приведение к int. В итоге компилятор понимает, что это число и перестаёт ворчать. Это именно для вывода.

        Другое место, где могут возникнуть предупреждения, это сужения типов. При неявном приведении из большого числа к меньшему, компилятор будет ворчать. В таких случаях использую явное приведение static_cast.
          Всем спасибо за помощь!
          Действительно, замена char на signed char привела к отмене множества предупреждений!
          И вообще теперь буду внимательнее работать с этими типами данных.
          Раньше я вообще думал, что слово "signed" в C/C++ добавлено "для красоты" и его всегда можно опустить.
          Как видим, не всегда. Это служебное слово учит программиста аккуратности.
            Цитата mkudritsky @
            я вообще думал, что слово "signed" в C/C++ добавлено "для красоты" и его всегда можно опустить.
            Как видим, не всегда.

            Для типа char signed действительно имеет значение. В других случаях его действительно можно опустить. Типы: "int", "signed" и "signed int" являются одним и тем же типом.
              Откройте для себя удивительный мир stdint.h и навсегда забудьте о всех signed/unsigned char, int, long, long long. В хорошо написанной программе должны быть только типы из stdint.h и char (для хранения символов).
                Цитата Dushevny @
                Откройте для себя удивительный мир stdint.h и навсегда забудьте о всех signed/unsigned char, int, long, long long. В хорошо написанной программе должны быть только типы из stdint.h и char (для хранения символов).

                В принципе верно с оговорками. Про базовую целочисленную арифметику соглашусь и поддержу. Я подключаю cstdint, типы которого использую.

                Но принципы надо понимать. Всякие signed и unsigned это основы языка. Даже если они не используются в обычных случаях, то всё равно влияют.

                А на счёт символов тут спорно. В разных случаях использую char, wchar_t и даже char32_t. Одного char категорически мало.
                  Как раз для того, чтобы убрать неоднозначность, то ли малое целое, то ли символ, фикъегознает, что тут программист имел в виду, в Плюсах char сделали отдельным типом. Вам нужен символ – используйте char, нужно малое целое, добавьте к нему указание знаковости. Это здорово помогает в чтении исходников, ну а компилятор пытается в этом помогать.

                  Добавлено
                  P.S. Модификатор hh для типов вполне Стандартен, начиная с C99 и C++11. Можно пользоваться без ограничений.
                    Цитата 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 категорически мало.
                    Согласен.
                    Сообщение отредактировано: Dushevny -
                      Немного поясню, к чему я стремлюсь.
                      Сейчас принудительно пишу часть программ на классическом Си. Ну просто сам для себя решил, что надо поглубже освоить этот замечательный язык. И писать часть сложных программ без использования классов С++.
                      Ну а библиотека stdint.h, наверное, есть расширение классического синтаксиса Си (?). Пока в расширения классики не лезу.

                      Хотя и С++ очень нравится, особенно вектора, множества, итераторы, алгоритмы...
                      И все такое быстрое - не медленнее классического Си.

                      Цитата Qraizer @
                      Модификатор hh для типов вполне


                      Все равно %hhd отказывается без ругани и предупреждений читать signed char.
                      Пока примерно так действую:
                      ExpandedWrap disabled
                        short Nzk;                  // Число городов, которые должен обойти коммивояжер
                        signed char Ng;             // Число городов
                         
                        // Задание числа городов
                        printf("Число городов Nzk = ");
                        if (!scanf("%hd", &Nzk)) {
                            printf("Не могу прочитать число городов Nzk\n");
                            return -1;
                        }
                        Ng = (signed char)Nzk; // Тут в реальной программе проверка, чтобы -129 < Nzk < 128

                      Не знаю, мне почему-то дискомфортно, когда компилятор на ровном месте выдает предупреждения. Стараюсь этого избегать, по крайней мере в таких тривиальных участках кода.
                      Сообщение отредактировано: Qraizer -
                        Цитата mkudritsky @
                        Все равно %hhd отказывается без ругани и предупреждений читать signed char.
                        для этого нам свыше дан inttypes.h
                          Цитата mkudritsky @
                          Все равно %hhd отказывается без ругани и предупреждений читать signed char.
                          Ну если брать реализацию, которая не поддерживает C99 (а таких хватает), то эффект будет печальным. Смотри документацию на свои средства разработки.
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0381 ]   [ 17 queries used ]   [ Generated: 5.05.24, 23:47 GMT ]