переполнения в дополнениях size_t

Мне нравится, когда мое предупреждение о коде бесплатно для VS.NET и GCC, и мне нравится, когда мой код готов к 64-разрядной версии.

Сегодня я написал небольшой модуль, который работает с буферами памяти и обеспечивает доступ к данным через файловый интерфейс (например, вы можете читать байты, записывать байты, искать и т. д.).

В качестве типа данных для текущей позиции чтения и размера я использовал size_t, так как это кажется наиболее естественным выбором. Я обхожу предупреждения, и это должно работать и в 64-битной версии.

На всякий случай: моя структура выглядит так:

typedef struct
{
  unsigned char * m_Data;
  size_t          m_CurrentReadPosition;
  size_t          m_DataSize;
} MyMemoryFile;

Подпись size_t на практике, по-видимому, не определена. Поиск кода Google доказал это.

Теперь я перед дилеммой: я хочу проверить дополнения с size_t на наличие переполнения, потому что мне приходится иметь дело с данными, предоставленными пользователем, и сторонние библиотеки будут использовать мой код. Однако для проверки переполнения мне нужно знать знак. Это имеет огромное значение в реализации.

Итак, как, черт возьми, мне написать такой код независимо от платформы и компилятора?

Могу ли я проверить подписанность size_t во время выполнения или во время компиляции? Это решило бы мою проблему. Или, может быть, size_t изначально было не лучшей идеей.

Любые идеи?

EDIT: я ищу решение для C-языка!


person Nils Pipenbrinck    schedule 15.10.2008    source источник
comment
какую версию gcc вы используете? Похоже, они сделали size_t беззнаковым в версиях после 2.4 включительно   -  person Nicholas Mancuso    schedule 16.10.2008
comment
Версии, с которыми мне приходится иметь дело, повсюду. Я занимаюсь встроенным программированием, и иногда мне приходится использовать версии компилятора из каменного века.   -  person Nils Pipenbrinck    schedule 16.10.2008
comment
Подпись — обычное слово.   -  person Lassi    schedule 28.10.2016


Ответы (6)


Что касается того, является ли size_t подписанным или неподписанным и GCC (из старого руководства GCC - я не уверен, что он все еще там):

Существует потенциальная проблема с типом size_t и версиями GCC до выпуска 2.4. ANSI C требует, чтобы size_t всегда был беззнаковым типом. Для совместимости с заголовочными файлами существующих систем GCC определяет size_t в stddef.h как любой тип, определяемый системным sys/types.h. Большинство систем Unix, которые определяют size_t в sys/types.h, определяют его как подписанный тип. Некоторый код в библиотеке зависит от того, что size_t является беззнаковым типом, и не будет работать правильно, если он подписан.

Код библиотеки GNU C, который ожидает, что size_t будет беззнаковым, верен. Определение size_t как подписанного типа неверно. Мы планируем, что в версии 2.4 GCC всегда будет определять size_t как беззнаковый тип, а скрипт fixincludes будет массировать системный sys/types.h, чтобы не конфликтовать с этим.

Тем временем мы обходим эту проблему, явно указав GCC использовать беззнаковый тип для size_t при компиляции библиотеки GNU C. 'configure' автоматически определит, какой тип GCC использует для size_t аранжировки, чтобы при необходимости переопределить его.

Если вам нужна подписанная версия size_t, используйте ptrdiff_t, или в некоторых системах есть typedef для ssize_t.

person Michael Burr    schedule 15.10.2008
comment
Пришлось сделать это из собственного любопытства - мне было трудно поверить, что GCC проигнорирует довольно простую часть стандарта без достойного объяснения. - person Michael Burr; 16.10.2008

size_t — это целочисленный тип без знака в соответствии со стандартами C++ C. Любая реализация с подписью size_t серьезно не соответствует требованиям и, вероятно, имеет другие проблемы с переносимостью. При переполнении он гарантированно завершается, а это означает, что вы можете написать такие тесты, как if (a + b < a), чтобы найти переполнение.

size_t — отличный тип для всего, что связано с памятью. Ты делаешь это правильно.

person David Thornley    schedule 15.10.2008

size_t не должно быть подписано.

Обычно он определяется как unsigned long.

Я никогда не видел, чтобы это определялось иначе. ssize_t является его подписанным аналогом.

РЕДАКТИРОВАТЬ: GCC определяет его как подписанный в некоторых обстоятельствах. компиляция в режиме ASNI C или std-99 должна сделать его беззнаковым.

person Nicholas Mancuso    schedule 15.10.2008
comment
GCC определяет size_t как подписанный :( - person Nils Pipenbrinck; 16.10.2008
comment
Разве unsigned long 32 бита в 64-битных окнах? Не очень хорошее предположение для size_t. - person ejgottl; 16.10.2008
comment
g++ 4.2.3 определяет его как беззнаковый. - person ejgottl; 16.10.2008
comment
Как возникла эта проблема в 2008 году? Последняя версия GCC, которая (ошибочно) определяла size_t как подписанную, устарела более 10 лет назад. - person R.. GitHub STOP HELPING ICE; 04.03.2012


Используйте safeint. Это класс, разработанный Майклом Ховардом и выпущенный Microsoft с открытым исходным кодом. Он предназначен для работы с целыми числами, когда переполнение определяется как риск. Все переполнения преобразуются в исключения и обрабатываются. Класс предназначен для облегчения правильного использования.

Например :

char CouldBlowUp(char a, char b, char c)
{
   SafeInt<char> sa(a), sb(b), sc(c);

   try
   {
     return (sa * sb + sc).Value();
   }
   catch(SafeIntException err)
   {
      ComplainLoudly(err.m_code);
   }

   return 0;
}

Кроме того, safeint часто используется внутри Microsoft в таких продуктах, как Office.

Ссылка: текст ссылки

person 1800 INFORMATION    schedule 15.10.2008
comment
Я не могу использовать SaveInt. Я работаю только на C, и afaik saveint также не решает проблему знака, поскольку принимает значения по умолчанию из msvc. - person Nils Pipenbrinck; 16.10.2008
comment
Ах да, вопрос изначально был помечен как C++. См. мой другой ответ для библиотеки языка C. - person 1800 INFORMATION; 16.10.2008
comment
Да, я знаю. Извини за это. Я отредактировал вопрос, чтобы никого не вводить в заблуждение. - person Nils Pipenbrinck; 16.10.2008

Я не уверен, правильно ли я понимаю вопрос, но, возможно, вы можете сделать что-то вроде:

temp = value_to_be_added_to;

value_to_be_added_to += value_to_add;

if (temp > value_to_be_added_to)
{
  overflow...
}

Поскольку он вернется к более низким значениям, вы можете легко проверить, не переполнился ли он.

person Francisco Soto    schedule 15.10.2008
comment
Что, если значение value_to_add отрицательно? - person Dour High Arch; 16.10.2008