Разве на простые 64-битные сломается много разумного кода?

StackOverflow https://stackoverflow.com/questions/4559251

  •  14-10-2019
  •  | 
  •  

Вопрос

До недавнего времени я рассматривал решение большинства системных импеллеров/поставщиков int 32-битный даже на 64-битных машинах своего рода целесообразной бородавки. С современными типами фиксированного размера C99 (int32_t а также uint32_t, и т. Д.) Необходимость, чтобы быть стандартным целочисленным типом каждого размера 8, 16, 32 и 64 в основном исчезает, и это похоже на int С таким же успехом можно было бы сделать 64-битный.

Однако самое большое реальное следствие размера простого int в C происходит от того факта, что C, по сути, не имеет арифметики на меньшем, чемint типы В частности, если int больше 32-битного, в результате любой арифметики на uint32_t Значения имеют тип signed int, что довольно тревожно.

Это веская причина сохранить int Постоянно исправлено на 32-битной реализации в реальном мире? Я склоняюсь к тому, чтобы сказать да. Мне кажется, что может быть огромный класс использования uint32_t который сломается, когда int больше 32 бит. Даже применение уникального минус или битового оператора комплемента становится опасным, если вы не отбросите обратно в uint32_t.

Конечно, те же проблемы применяются к uint16_t а также uint8_t При текущих реализациях, но все, кажется, знают и привыкли относиться к ним как «меньше, чемint"Типы.

Это было полезно?

Решение

Как вы говорите, я думаю, что правила продвижения по службе действительно являются убийцей. uint32_t тогда продвигал int И вдруг вы бы подписали арифметику, где почти все ожидают без подписи.

Это было бы в основном скрыто в местах, где вы просто арифметику и обратно обратно uint32_t. Анкет Но это может быть смертельным в местах, где вы сравниваете константы. Является ли код, который зависит от таких сравнений без явного состава, разумно, я не знаю. Кастинг постоянных, как (uint32_t)1 может стать довольно утомительным. Я лично, по крайней мере, всегда использую суффикс U Для постоянных, которые я хочу быть без подписи, но это уже не так читаемо, как мне хотелось бы.

Также имеют в виду, что uint32_t и т. д. не гарантированно. Даже не uint8_t. Анкет Применение этого является расширением от POSIX. Таким образом, в этом смысле C как язык далеко не способен сделать этот шаг.

Другие советы

"Разумный код" ...

Ну ... вещь о разработке, вы пишете и исправляете это, а затем это работает ... и затем вы останавливаетесь!

И, может быть, вас много сгорели, поэтому вы остаетесь хорошо в безопасных диапазонах определенных функций, и, возможно, вы не были сожжены в такой конкретный путь Таким образом, вы не понимаете, что полагаетесь на что-то, что может измениться.

Или даже то, что вы полагаетесь на ошибку.

На компиляторах Olden Mac 68000 INT был 16 -битный, а длинный был 32. Но даже тогда большинство существующих C -кода предполагал, что INT составлял 32, поэтому типичный код, который вы обнаружили в группе новостей, не сработает. (О, и у Mac не было Printf, но я отступаю.)

Итак, я получаю, да, если вы измените что-либо, тогда некоторые вещи сломаются.

С современными типами фиксированного размера C99 (Int32_T и UINT32_T и т. Д.) Необходимость, чтобы быть стандартным целочисленным типом каждого размера 8, 16, 32 и 64 в основном исчезает,

C99 имеет типы фиксированного размера, а не типы фиксированного размера. Нативные типы целочисленных целого числа все еще char, short, int, long, а также long long. Анкет Они все еще актуальны.

Проблема с ILP64 заключается в том, что он имеет большое несоответствие между типами C и C99 Typedefs.

  • int8_t = char
  • int16_t = короткий
  • int32_t = Нестандартный тип
  • int64_t = int, длинный или длинный

Из 64-битные модели программирования: почему LP64?:

К сожалению, модель ILP64 не предоставляет естественный способ описания 32-разрядных типов данных и должна прибегнуть к невоздумым конструкциям, таким как __int32 Чтобы описать такие типы. Это может вызвать практические проблемы при производстве кода, который может работать как на 32, так и 64 -битных платформах без #ifdef конструкции. Было возможно переносить большое количество кода в модели LP64 без необходимости вносить такие изменения, сохраняя при этом инвестиции, сделанные в наборах данных, даже в тех случаях, когда информация о типинге не была сделана извне приложением.

Dec Alpha и OSF/1 Unix были одной из первых 64-битных версий UNIX, и он использовал 64-разрядные целые числа-архитектура ILP64 (значение int, long и все указатели были 64-разрядными количествами). Это вызвало много проблем.

Одна проблема, которую я не видел, упомянут - поэтому я вообще отвечаю так долго - это то, что если у вас есть 64 -битная int, какой размер вы используете для short? Оба 16 бит (классические, ничего не подходят) и 32 бита (хорошо, хорошо, short должно быть вдвое меньше, чем int'Подход) представит некоторые проблемы.

С C99 <stdint.h> а также <inttypes.h> Заголовок, вы можете кодировать целыми числам фиксированного размера-если вы решите игнорировать машины с 36-битными или 60-битными целыми числами (что, по крайней мере, квази-регитиматическое). Тем не менее, большая часть кода не написана с использованием этих типов, и в коде, как правило, существуют глубоко укоренившиеся и в значительной степени скрытые (но принципиально ошибочные) предположения, которые будут расстроены, если модель отходит от существующих вариаций.

Обратите внимание на модель Microsoft Ultra-Conservative LLP64 для 64-битных Windows. Это было выбрано, потому что слишком много старого кода сломался бы, если бы 32-разрядная модель была изменена. Тем не менее, код, который был перенесен в архитектуру ILP64 или LP64, не был сразу же переносимы в LLP64 из -за различий. Теоретики заговора, вероятно, скажут, что он был намеренно выбрано, чтобы затруднить то, чтобы код, написанный для 64-разрядного UNIX, был перенесен в 64-разрядные окна. На практике я сомневаюсь, что это было больше, чем счастливый (для Microsoft) побочный эффект; 32-разрядный код Windows должен был быть пересмотрен, чтобы использовать модель LP64.

Есть одна идиома кода, которая бы сломалась, если бы INT были 64-битными, и я вижу ее достаточно часто, что я думаю, что это можно было бы назвать разумным:

  • проверить, является ли значение отрицательным, тестируя, если ((val & 0x80000000) != 0)

Это обычно встречается при проверке кодов ошибок. Много стандартов кода ошибок (например, Window HRESULT) использует бит 31 для представления ошибки. И код иногда проверяет эту ошибку либо путем тестирования бита 31, либо иногда проверяя, является ли ошибка отрицательным номером.

Макросы Microsoft для тестирования HResult Используют оба метода - и я уверен, что существует тонна кода, который делает одинаковую без использования макросов SDK. Если бы MS перешел в ILP64, это была бы одна область, которая вызвала портирующую головную боль, которой полностью избегают модели LLP64 (или модели LP64).

ПРИМЕЧАНИЕ. Если вы не знакомы с такими терминами, как «ILP64», см. Мини-Глоссарий в конце ответа.

Я почти уверен, что существует много кода (не обязательно ориентированного на Windows), в котором используется обычный старик для хранения кодов ошибок, предполагая, что эти INT имеют 32-битный размер. И держу пари, что есть много кода с этой схемой состояния ошибки, которая также использует оба вида проверки (< 0 и бит 31 установлен) и который сломается, если перенесено на платформу ILP64. Эти проверки могут быть сделаны для того, чтобы продолжать работать правильно в любом случае, если коды ошибок были тщательно построены, чтобы провести вытяжение знака, но, опять же, многие такие системы, которые я видел, строили значения ошибки, или собрав кучу кучу. Анкет

В любом случае, я не думаю, что это неразрешимая проблема каким -либо образом, но я думаю, что это довольно распространенная практика кодирования, которая приведет к тому, что много кода потребует исправления, если перенесено на платформу ILP64.

Обратите внимание, что я также не думаю, что это была одна из главных причин для Microsoft выбрать модель LLP64 (я думаю, что это решение было в значительной степени обусловлено совместимостью бинарных данных между 32-битными и 64-битными процессами, как упоминается в MSDN а также В блоге Раймонда Чена).


Мини-Глоссарий Для 64-битной терминологии программирования платформы:

  • ILP64: int, long, указатели 64-бит
  • LP64: long и указатели 64 бита, int 32-битные (используются многими (большинство?) Unix платформами)
  • LLP64: long long и указатели 64 бита, int а также long Оставаться 32-битным (используется на Win64)

Для получения дополнительной информации о 64-битных моделях программирования см. "64-битные модели программирования: почему LP64?"

Хотя я лично не пишу код, так, держу пари, что он существует в нескольких местах ... и, конечно, он сломается, если вы измените размер int.

int i, x = getInput();
for (i = 0; i < 32; i++)
{
    if (x & (1 << i))
    {
        //Do something
    }
}

Ну, это не так, как эта история - все новая. С «большинством компьютеров» я предполагаю, что вы имеете в виду настольные компьютеры. Уже было переход от 16-битного до 32-битного int. Анкет Есть ли что -то вообще, что говорит о том, что такая же прогресс не произойдет на этот раз?

Не особенно. INT составляет 64 бит на около 64 -битных архитектуры (не X64).

Стандарт на самом деле не гарантирует, что вы получите 32 -битные целые числа, только это (u) int32_t может удерживать один.

Теперь, если вы зависите от int, такой же размер, что и ptrdiff_t, вы можете быть сломаны.

Помните, C не гарантирует, что машина даже является бинарной машиной.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top