2014-11-07 2 views
3

У меня есть следующий метод C, который принимает два 16-битных коротких Интс и:Доступ к флагам без встроенной сборки?

  • добавляет два целых числа
  • Если флаг переноса установлен, добавить 1 к результату
  • NEGATE (НЕ) все биты в конечных результатах
  • возвращает результат:

    short __declspec(naked) getchecksum(short s1, short s2) 
    { 
        __asm 
        { 
         mov ax, word ptr [esp+4] 
         mov bx, word ptr [esp+8] 
         add ax, bx 
         jnc skip_add 
         add ax, 1 
         skip_add: 
         not ax  
         ret 
        } 
    } 
    

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

+1

Хотя не ответ на ваш вопрос, не могли бы вы использовать 'АЦП топором, 0' и удалите 'jnc skip_add',' add ax, 1', 'skip_add:'. 'adc ax, 0' добавит' 0' к 'ax', а затем добавит 1 к этому результату, если установлен флаг переноса. Еще одна проблема с кодом заключается в том, что 'bx' изменяется, а соглашения о вызовах' cdecl' требуют, чтобы функция bx' сохранялась вызываемой функцией (то есть 'push/pop bx') или использовала регистр, который не нужен сохраняются функцией (например, 'cx' или' dx'). Вы можете написать 'add ax, bx', чтобы устранить необходимость в' bx' с 'add ax, word ptr [esp + 8]' и удалить 'mov' в' bx' вообще –

ответ

5

Нет (C вообще не имеет флагов), но это не значит, что вы не можете получить тот же результат. Если вы используете 32-битные целые числа для добавления, 17-й бит - это перенос. Поэтому вы можете написать это так:

uint16_t getchecksum(uint16_t s1, uint16_t s2) 
{ 
    uint32_t u1 = s1, u2 = s2; 
    uint32_t sum = u1 + u2; 
    sum += sum >> 16; 
    return ~sum; 
} 

Я сделал типы неподписанными для предотвращения неприятностей. Возможно, это не обязательно на вашей платформе.

3

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

short __declspec(naked) getchecksum(short s1, short s2) 
{ 
    short s = s1 + s2; 
    if ((unsigned short)s < (unsigned short)s1) 
     s++; 
    return ~s; 
} 

Есть уже много вопросов о добавлении и проведении на SO: Efficient 128-bit addition using carry flag, Multiword addition in C

Однако в C операции всегда выполняются, по крайней мере, в int-типе, поэтому вы можете просто добавить, что если int имеет более 16 бит в вашей системе. В вашем случае встроенная сборка - 16-разрядная x86, поэтому я думаю, что вы находитесь на Turbo C, который должен быть удален ASAP (причина: Why not to use Turbo C++?). В других системах, которые 16-битный Int вы можете использовать длинные, который гарантированно будет по крайней мере 32 бита стандартной

short __declspec(naked) getchecksum(short s1, short s2) 
{ 
    long s = s1 + s2; 
    return ~((s & 0xffff) + ((s >> 16) & 0x1)); 
} 
+0

Не удалось 's >> 16' на самом деле дать вам -1? – harold

+1

@harold строго говоря, это реализация определена, но да, она, скорее всего, станет -1, если сумма отрицательная. Исправлено: –

+0

Это на самом деле MSVC. Я использую 32-разрядный указатель на стек 'esp', но 16-битные регистры GP, потому что шорты имеют 16-разрядную ширину –

Смежные вопросы