Длинный длинный в c99

Jan 10 2021

В стандарте C99 они ввели long long. Какая у этого цель? В моем (ограниченном) опыте программирования на C я видел только 4-байтовые int и 8-байтовые. Например, из Compiler Explorer:

Если longуже, 8то зачем добавлять другой long longтип? Что это делает с компилятором / архитектурой?

Ответы

6 chux-ReinstateMonica Jan 10 2021 at 05:36

Если long уже 8, то зачем добавлять еще один длинный длинный тип? Что это делает с компилятором / архитектурой?

«Если long уже 8» не всегда верно, так как существует много кода, основанного на 32-битном коде, longа intтакже на 32- или 16-битном.

Требование long64-битной версии нарушило бы кодовую базу. Это серьезная проблема.


Тем не менее, требование longоставаться 32-битным (и нет long long) не приведет к доступу к стандартным 64-битным целым числам, следовательно, обоснование для long long.

Разрешение long32-битной или 64-битной (или других) разрешает переход.

Различные функции передаются / возвращаются longвроде fseek(), ftell(). Они выигрывают от longтого, что они более 32-битные для поддержки больших файлов.

Рекомендуемая практика поощряет более широкое long: «Типы, используемые для size_tи ptrdiff_tне должны иметь ранг целочисленного преобразования выше, чем у, signed long intесли реализация не поддерживает объекты, достаточно большие, чтобы сделать это необходимым». Это относится к объемам памяти, превышающим 32 бита.


Возможно, в будущем реализация может использовать int/long/long long/intmax_tкак 32/64/128/256 бит.

IAC, я вижу, что типы фиксированной ширины intN_tстановятся все более популярными по сравнению с longи long long. Я обычно использую типы фиксированной ширины or bool, ( unsigned) char, int/ unsigned,, size_t( u) intmax_tи leave signed char, ( unsigned) short, ( unsigned) long, ( unsigned) long longдля особых случаев.

4 dbush Jan 10 2021 at 05:26

Стандарт C гарантирует только то, что an intможет быть (грубо говоря) 2 байтами, a longможет быть 4 байтами, а a long longможет быть 8 байтами.

Фактически, MSVC по-прежнему использует 4 байта, longхотя имеет 4 байта int.

3 NateEldredge Jan 10 2021 at 05:38

Единственное соответствующее требование для intи longтогда и сейчас - это intдолжно быть не менее 16 бит и longдолжно быть не менее 32 бит. И 16-, и 32-битные системы обычно имеют 32-битные long, а 64-битные машины были гораздо менее распространены в конце 1990-х годов. Таким образом, до C99 программисты вообще не могли полагаться на доступный 64-битный целочисленный тип. Эта проблема была решена введением long long, которое должно быть не менее 64 бит. (Я считаю, что он уже был предоставлен GCC и, возможно, другими компиляторами в качестве расширения).

В наши дни многие (но не все) 64-битные системы используют 64-битные longи не пытаются long longувеличивать их, поэтому они также 64-битные и в некотором смысле избыточны. Предположительно, это системы, с которыми вы знакомы, но они не отражают все, что есть.

2 PeterCordes Jan 10 2021 at 10:29

Я думаю, вы не осознавали, что делаете огромное неверное предположение о том, как работают требования к ширине типа C: ISO C просто устанавливает минимальный диапазон значений, например, наименьшее допустимое значение LONG_MAXи LONG_MIN(-2147483647, а не 8, потому что ISO C позволяет дополнять целые числа со знаком / величиной со знаком, а не только дополнять до 2). Фактические реализации могут иметь более широкие типы, часто для соответствия ширине регистра или размеру операнда, которые целевая машина может эффективно выполнять.

Об этом много написано в Stack Overflow и в других местах, и я не собираюсь повторять здесь. Смотрите такжеhttps://en.cppreference.com/w/c/language/arithmetic_types


Это привело вас к ошибке, когда вы смотрели на выбор ширины шрифта в x86-64 System V ABI и предполагали, что другие реализации C такие же, я думаю. x86-64 - это 64-битный ISA, который может эффективно работать с 64-битными целыми числами, поэтому 64-битная версия longбыла вполне разумным выбором.

Ни один нормальный ABI для 32-битной машины, такой как i386, не будет использовать 64-битную, longпотому что это не требуется, только 32-битная. Использование 64-битной версии означало бы, что она не могла поместиться в один регистр. Скомпилируйте -m32или скомпилируйте для 32-битной ARM. Godbolt также имеет GCC для AVR и MSP430. На этих 8-битных и 16-битных машинах GCC выбирает наименьшую ширину, разрешенную ISO C (2 байта intи т. Д.).

В 1999 году x86-64 даже не существовало. (Несколько других 64-битных ISA сделали, например Alpha). Так что, глядя на один из двух основных ABI, чтобы понять, какие варианты выбора C99, вы далеко не уедете.

Конечно, C нужен тип, который гарантированно будет как минимум 64-битным, чтобы люди могли писать программы, которые эффективно выполняют 64-битную целочисленную математику.


И, кстати, x86-64 может делать 32-битные целые числа так же эффективно, как 64-битные, иногда более эффективно. Так что longсоздание 64-битного типа, пожалуй, не очень хорошо. Некоторый код использует, longпотому что им нужен тип, который должен быть 32-битным, но не выигрывает от его более широкого. Для такого кода 64-разрядная longверсия просто тратит впустую объем кеш-памяти / пропускную способность памяти и размер кода (префиксы REX). В C99 был бы идеальный выбор int_least32_t, но это раздражающе долго печатать и редко используется.

Но longиногда надеются, что OTOH будет «наиболее эффективным (с 1 регистром) типом», хотя такой гарантии нет, и ABI LLP64, такие как Windows x64 с 32-разрядной версией long, не такие.

Еще одна целая банка червей - int_fast32_tэто плохой выбор IMO для C99 и x86-64 System V, чтобы сделать этот тип 64-битным. (У меня есть наполовину написанный ответ для Cpp uint32_fast_t разрешается в uint64_t, но медленнее почти для всех операций, чем uint32_t (x86_64). Почему он разрешается в uint64_t? Который я должен закончить ... int_fast32_tподнимает вопрос «быстро для чего цель ", и во многих реализациях это не то, на что можно надеяться во многих случаях.

Смотрите также

  • C ++ - самый быстрый целочисленный тип?
  • Как следует определять типы [u] int_fastN_t для x86_64, с ABI для x32 или без него?
  • Почему uint32_t предпочтительнее uint_fast32_t?
  • Почему uint_least16_t быстрее, чем uint_fast16_t для умножения в x86_64?
  • Оптимизация компилятора разрешена с помощью типов "int", "минимум" и "fast" с нефиксированной шириной C / C ++
old_timer Jan 11 2021 at 06:16

Существуют некоторые ограничения, но автор компилятора может выбирать длины для стандартных типов переменных C (char, short, int, long, long long). Естественно, что char будет байтом для этой архитектуры (большинство компиляторов C имеют 8 бит). И, естественно, что-то меньшее не может быть больше, чем что-то большее, long не может быть меньше int. Но, безусловно, к 1999 году мы увидели переход x86 с 16 на 32 бит, и, например, int изменился с 16 на 32 с помощью ряда инструментов, но долгое время оставался 32. Позже произошел переход с 32 на 64 бит x86, и в зависимости от инструмента были доступны типы помогать.

Проблема существовала задолго до этого, и решение состояло не в том, чтобы фиксировать длину типов, они, в пределах правил, устанавливаются авторами компилятора в отношении размера. Но авторам компилятора необходимо создать файл stdint.h, который соответствует инструменту и цели (stdint.h как минимум специфичен для инструмента и цели и может быть версией инструмента и опциями сборки для этого инструмента и т. Д.). Так что, например, uint32_t всегда 32 бита. Некоторые авторы преобразуют это в int, другие в long и т. Д. В своем stdint.h. Типы переменных языка C по-прежнему ограничены char, short, int и т. Д. Для каждого языка (uint32_t не является типом переменной, он преобразуется в тип переменной через stdint.h). Это решение / обходной путь был способом уберечь всех от сумасшествия и сохранить язык.

Авторы часто выбирают, например, если GPR 16-битные, чтобы int было 16-битным, а если 32-битное было 32-битным и так далее, но у них есть некоторая свобода.

Да, это конкретно означает, что нет причин предполагать, что любые два инструмента для конкретной цели (например, компьютер, на котором вы читаете это) используют одни и те же определения для int и long, в частности, и если вы хотите написать код для эта платформа, которая может переносить эти инструменты (которые поддерживают эту платформу), затем используйте типы stdint.h, а не int, long и т.д ... Скорее всего, если вы пересекаете платформы, msp430 mcu, arm mcu, arm linux машина , машина на базе x86, типы которой, даже для одной и той же "цепочки инструментов" (например, gnu gcc и binutils), не имеют одинаковых определений для int и long и т. д. char и short, как правило, 8- и 16-битные, int и long имеют тенденцию сильно различаться, иногда одного и того же размера, иногда разного, но дело не в том, чтобы предполагать.

Определить размеры для версии компилятора / цели / параметров командной строки - тривиально или просто перейти по маршруту stdint, чтобы впоследствии минимизировать проблемы.