Вопрос

Большая часть кода, который я когда-либо читал, использует int для стандартной обработки ошибок (возвращаемые значения из функций и т.п.).Но мне интересно, есть ли какая-либо польза от использования uint_8 будет компилятор - читайте:большинство компиляторов C на большинстве архитектур создают инструкции, используя режим немедленной адреса, т. е. встраивают 1-байтовое целое число в инструкцию?Ключевая инструкция, о которой я думаю, — это сравнение после возврата функции, использующей uint_8 в качестве типа возвращаемого значения.

Возможно, я неправильно думаю о вещах, поскольку введение 1-байтового типа просто вызывает проблемы с выравниванием - вероятно, существует совершенно разумная причина, по которой компиляторы любят упаковывать вещи в 4 байта, и это, возможно, причина, по которой все просто используют целые числа - и поскольку это проблема, связанная со стеком, а не с кучей, реальных накладных расходов нет.

Я думаю о том, как поступить правильно.Но допустим, в качестве аргумента, это популярный дешевый микропроцессор для умных часов, и он оснащен 1 КБ памяти, но имеет разные режимы адресации в своем наборе команд :D

Еще один вопрос, позволяющий немного конкретизировать обсуждение (x86):является литералом в:

uint_32 x=func(); x==1;

и

uint_8 x=func(); x==1;

того же типа?или во втором случае компилятор сгенерирует 8-байтовый литерал.Если это так, он может использовать его для создания инструкции сравнения, которая имеет литерал в качестве непосредственного значения и возвращаемое целое число в качестве ссылки на регистр. См. типы инструкций CMP..

Еще одна ссылка на набор инструкций x86.

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

Решение

Вот что сделает один конкретный компилятор для следующего кода:

extern int foo(void) ;
void bar(void)
{
        if(foo() == 31) { //error code 31
                do_something();
        } else {
                do_somehing_else();
        }
}

   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 08                sub    $0x8,%esp
   6:   e8 fc ff ff ff          call   7 <bar+0x7>
   b:   83 f8 1f                cmp    $0x1f,%eax
   e:   74 08                   je     18 <bar+0x18>
  10:   c9                      leave
  11:   e9 fc ff ff ff          jmp    12 <bar+0x12>
  16:   89 f6                   mov    %esi,%esi
  18:   c9                      leave
  19:   e9 fc ff ff ff          jmp    1a <bar+0x1a>

3-байтовая инструкция для cmp.Если foo () возвращает символ, мы получаем B:3c 1f cmp $0x1f,%al

Если вы ищете эффективность, хотя.Не думайте, что сравнение данных в %a1 происходит быстрее, чем сравнение с %eax.

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

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

И если в приведенном вами примере вы говорите о x86, вы делаете ложное предположение:Немедленное должно быть типа uint8_t.

На самом деле 8-битные непосредственные инструкции, встроенные в инструкцию, имеют тип int8_t и может использоваться с байтами, словами, dword и qwords в нотации C: char, short, int и long long.

Так что на этой архитектуре не было бы вообще никакой выгоды, ни размера кода, ни скорости выполнения.

Для вычислений следует использовать типы int или unsigned int.Использование меньших типов только для соединений (структур/массивов).Причина этого в том, что int обычно определяется как «наиболее естественный» целочисленный тип для процессора, а для корректной работы любого другого производного типа может потребоваться обработка.В нашем проекте, скомпилированном с помощью gcc в Solaris для SPARC, был случай, когда доступ к 8- и 16-битным переменным добавлял инструкцию в код.При загрузке меньшего типа из памяти необходимо было убедиться, что верхняя часть регистра установлена ​​правильно (расширение знака для знакового типа или 0 для беззнакового типа).Это сделало код длиннее и увеличило нагрузку на регистры, что ухудшило результаты других оптимизаций.

У меня есть конкретный пример:

Я объявил две переменные структуры как uint8_t и получил этот код в Sparc Asm:

    if(p->BQ > p->AQ)

был переведен на

ldub    [%l1+165], %o5  ! <variable>.BQ,
ldub    [%l1+166], %g5  ! <variable>.AQ,
and     %o5, 0xff, %g4  ! <variable>.BQ, <variable>.BQ
and     %g5, 0xff, %l0  ! <variable>.AQ, <variable>.AQ
cmp     %g4, %l0    ! <variable>.BQ, <variable>.AQ
bleu,a,pt %icc, .LL586  !

И вот что я получил, когда объявил две переменные как uint_t

lduw    [%l1+168], %g1  ! <variable>.BQ,
lduw    [%l1+172], %g4  ! <variable>.AQ,
cmp     %g1, %g4    ! <variable>.BQ, <variable>.AQ
bleu,a,pt %icc, .LL587  !

На две арифметические операции меньше и на 2 регистра больше для прочего.

Процессоры обычно предпочитают работать со своими естественными размерами регистров, которыми в C является «int».

Хоть и есть исключения, но вы слишком много думаете о проблеме, которой не существует.

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