Должен ли я использовать целочисленные типы stdint.h на 32/64 битных машинах?

Одна вещь, которая беспокоит меня в обычных объявлениях целых чисел c, заключается в том, что их имена странные, худшее из которых - long long. Я создаю только для 32- и 64-битных машин, поэтому мне не обязательно нужна переносимость, которую предлагает библиотека, однако мне нравится, что имя для каждого типа представляет собой одно слово одинаковой длины без двусмысленности в размере.

// multiple word types are hard to read
// long integers can be 32 or 64 bits depending on the machine

unsigned long int foo = 64;
long int bar = -64;

// easy to read
// no ambiguity

uint64_t foo = 64;
int64_t bar = -64;

На 32- и 64-битных машинах:

1) Может ли использование меньшего целого числа, такого как int16_t, быть медленнее, чем что-то большее, например int32_t?

2) Если мне нужно, чтобы цикл for запускался всего 10 раз, можно ли использовать наименьшее целое число, которое может его обработать, вместо типичного 32-битного целого числа?

for (int8_t i = 0; i < 10; i++) {

}

3) Когда я использую целое число, которое, как я знаю, никогда не будет отрицательным, можно ли предпочесть версию без знака, даже если мне не нужен дополнительный диапазон в предоставленных?

// instead of the one above
for (uint8_t i = 0; i < 10; i++) {

}

4) Безопасно ли использовать typedef для типов, включенных из stdint.h

typedef int32_t signed_32_int;
typedef uint32_t unsigned_32_int;

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


person YeOldeBitwise    schedule 11.04.2017    source источник
comment
смотрели ли вы на stackoverflow.com/ questions / 9834747 /?   -  person Nic    schedule 11.04.2017
comment
Возможный дубликат Причины использования (или отказа) stdint   -  person Alex Lop.    schedule 11.04.2017
comment
Они похожи, однако у меня были некоторые конкретные вопросы о том, как их реализовать, на которые нет четкого ответа в этом посте. Кроме того, верхний ответ из этого сообщения звучит так, как будто вы не ошибетесь с фиксированными типами, но это не обязательно верно в соответствии с двумя ответами ниже, которые уже прояснили это.   -  person YeOldeBitwise    schedule 11.04.2017
comment
stackoverflow.com/questions/163254/   -  person 4386427    schedule 11.04.2017


Ответы (3)


1) Может ли использование меньшего целого числа, такого как int16_t, быть медленнее, чем что-то большее, например int32_t?

Да, может быть и медленнее. Вместо этого используйте int_fast16_t. При необходимости профилируйте код. Производительность очень зависит от реализации. Основным преимуществом int16_t является его небольшой, четко определенный размер (также он должен быть дополнением до 2), используемый в структурах и массивах, не столько для скорости.

Имя typedef int_fastN_t обозначает самый быстрый целочисленный тип со знаком шириной не менее N. C11 §7.20.1.3 2


2) Если мне нужно, чтобы цикл for запускался всего 10 раз, можно ли использовать наименьшее целое число, которое может его обработать, вместо типичного 32-битного целого числа?

Да, но такая экономия кода и скорости сомнительна. Предложите вместо этого int. Выпущенный код имеет тенденцию быть оптимальным по скорости / размеру с исходным размером int.


3) Всякий раз, когда я использую целое число, которое, как я знаю, никогда не будет отрицательным, можно ли предпочесть версию без знака, даже если мне не нужен дополнительный диапазон в предоставленных?

Использование некоторого беззнакового типа предпочтительнее, когда математика строго беззнаковая (например, индексирование массива с помощью size_t), но код должен следить за небрежным приложением, например

for (unsigned i = 10 ; i >= 0; i--) // infinite loop

4) Безопасно ли использовать typedef для типов, включенных из stdint.h

Почти всегда. Типы вроде int16_t необязательны. Максимальная переносимость использует требуемые типы uint_least16_t и uint_fast16_t для кода для работы на редких платформах, которые используют ширину битов, такую ​​как 9, 18 и т. Д.

person chux - Reinstate Monica    schedule 11.04.2017
comment
Что касается необязательного: эти типы не являются обязательными. Однако, если реализация предоставляет целочисленные типы с шириной 8, 16, 32 или 64 бит, без битов заполнения и (для подписанных типов), которые имеют представление с дополнением до двух, она должна определять соответствующие имена typedef. (§ 7.20.1.1/3 N1570 quasi C11). Я думаю, что это соответствует практически любой реализации ... (в настоящее время) - person Daniel Jour; 11.04.2017

Может ли использование меньшего целого числа, такого как int16_t, быть медленнее, чем что-то большее, например int32_t?

да. Некоторые процессоры не имеют выделенных 16-битных арифметических инструкций; арифметика с 16-битными целыми числами должна эмулироваться с помощью последовательности инструкций в следующих строках:

r1 = r2 + r3
r1 = r1 & 0xffff

Тот же принцип применяется к 8-битным типам.

Используйте «быстрые» целочисленные типы в <stdint.h>, чтобы избежать этого - например, int_fast16_t даст вам целое число шириной не менее 16 бит, но может быть шире, если 16-битные типы неоптимальны.

Если мне нужно, чтобы цикл for запускался всего 10 раз, можно ли использовать наименьшее целое число, которое может его обработать, вместо типичного 32-битного целого числа?

Не беспокойтесь; просто используйте int. Использование более узкого типа на самом деле не экономит места и может вызвать проблемы в дальнейшем, если вы решите увеличить количество итераций до 127 и забудете, что переменная цикла использует узкий тип.

Всякий раз, когда я использую целое число, которое, как я знаю, никогда не будет отрицательным, можно ли предпочесть версию без знака, даже если мне не нужен дополнительный диапазон в предоставленных?

Лучше избегать. Некоторые идиомы C некорректно работают с целыми числами без знака; например, вы не можете написать цикл формы:

for (i = 100; i >= 0; i--) { … }

если i - беззнаковый тип, потому что i >= 0 всегда будет истинным!

Безопасно ли использовать typedef для типов, включенных в stdint.h

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

Привыкайте к <stdint.h> именам. Они стандартизированы, и их довольно легко набирать.

person Community    schedule 11.04.2017
comment
использование более узкого типа [...] - и использование типа шире, чем размер регистра процессора, может даже замедлить программу ... просто используйте int правильно в целом, одно исключение: если вы работаете с большими значениями, которые, возможно, не подходят в int, в таком случае можно было бы предпочесть [...] быстрые [...] типы. Лучше всего избегать - опять же исключение: for (i = 0; i ‹ref; ++ i) - если ref беззнаковый по какой-либо причине, вы избегаете сравнения значений со знаком и без знака, если i тоже без знака. - person Aconcagua; 11.04.2017

  1. Абсолютно возможно, да. На моем ноутбуке (Intel Haswell) в микробенчмарке, который считает от 0 до 65535 на двух регистрах 2 миллиарда раз, это занимает

    1.313660150s - ax dx (16-bit)
    1.312484805s - eax edx (32-bit)
    1.312270238s - rax rdx (64-bit)
    

    Незначительные, но повторяемые различия во времени. (Я написал тест на сборке, потому что компиляторы C могут оптимизировать его для другого размера регистров.)

  2. Он будет работать, но вам придется поддерживать его в актуальном состоянии, если вы измените границы, и компилятор C, вероятно, все равно оптимизирует его для того же кода сборки.

  3. Пока это правильный C, все в порядке. Имейте в виду, что переполнение без знака определено, а переполнение со знаком не определено, и компиляторы действительно используют это для оптимизации. Например,

    void foo(int start, int count) {
        for (int i = start; i < start + count; i++) {
            // With unsigned arithmetic, this will execute 0 times if
            // "start + count" overflows to a number smaller than "start".
            // With signed arithmetic, that may happen, or the compiler
            // may assume this loop always runs "count" times.
            // For defined behavior, avoid signed overflow.
        }
    
  4. да. Кроме того, POSIX предоставляет inttypes.h, который расширяет stdint.h некоторыми полезными функциями и макросами.

person ephemient    schedule 11.04.2017