Значение «знак игнорируется»; в документации _InterlockedCompareExchange

Документация для _InterlockedCompareExchange говорит по каждому параметру

Знак игнорируется.

Значит ли это, что числа как 0xffff а также 0x7fff (для 16-битной версии) будет считаться равным _InterlockedCompareExchange16 и т.д. по другим характеристикам ширины? Или это означает, что встроенные функции принимают как целые числа со знаком, так и без знака? Или что-то другое?

Если это не ошибка в документации, это кажется, по крайней мере, неоднозначным.

4

Решение

Знаковый бит не игнорируется, он сравнивается так же, как и другие биты.

..CompareExchange.. функции заботятся только о равенстве битов и не интерпретируют их каким-либо особым образом. В системах на базе x86 они реализованы с CMPXCHG/CMPXCHG8B инструкции и сравнивает регистр процессора с местом в памяти. Проблема знака становится вопросом о типах и передаче параметров, а не о самом сравнении.

Поскольку большинство взаимосвязанных функций также существуют как функции Windows API, мы можем сначала взглянуть на них. базовая версия принимает 32-битные параметры с LONG тип. Меньшие типы со знаком будут расширяться до 32 бит:

__declspec(noinline) void WINAPI Number(LONG val)
{
printf("Number: %5d %#.8x (%d bit)\n", val, val, sizeof(void*) * 8);
}
__declspec(noinline) INT16 WINAPI GetI16(INT16 num)
{
return num;
}

...

Number(0xffff); // Not sign extended
const INT16 numi16 = -42;
Number(numi16); // Optimized to 32-bit parameter by the compiler
Number(GetI16(-42)); // Use a helper function to prevent compiler tricks

и это печатает:

Number: 65535 0x0000ffff (64 bit)
Number:   -42 0xffffffd6 (64 bit)
Number:   -42 0xffffffd6 (64 bit)

32-битный x86:

; 1040 :    Number(0xffff);

00022 68 ff ff 00 00  push     65535          ; 0000ffffH
00027 e8 00 00 00 00  call     ?Number@@YGXJ@Z        ; Number

; 1041 :    const INT16 numi16 = -42;
; 1042 :    Number(numi16);

0002c  6a d6           push     -42            ; ffffffd6H
0002e  e8 00 00 00 00  call     ?Number@@YGXJ@Z        ; Number
; 1047 :    Number(GetI16(-42));

00033  6a d6           push     -42            ; ffffffd6H
00035  e8 00 00 00 00  call     ?GetI16@@YGFF@Z        ; GetI16
0003a  0f bf c0        movsx  eax, ax
0003d  50              push     eax
0003e  e8 00 00 00 00  call     ?Number@@YGXJ@Z        ; Number

64-разрядная версия x86_64 / AMD64:

; 1040 :    Number(0xffff);

00027 b9 ff ff 00 00  mov  ecx, 65535     ; 0000ffffH
0002c e8 00 00 00 00  call     ?Number@@YAXJ@Z        ; Number

; 1041 :    const INT16 numi16 = -42;
; 1042 :    Number(numi16);

00031 b9 d6 ff ff ff  mov  ecx, -42       ; ffffffffffffffd6H
00036 e8 00 00 00 00  call     ?Number@@YAXJ@Z        ; Number

; 1047 :    Number(GetI16(-42));

0003b 66 b9 d6 ff     mov  cx, -42        ; ffffffffffffffd6H
0003f e8 00 00 00 00  call     ?GetI16@@YAFF@Z        ; GetI16
00044 0f bf c8        movsx    ecx, ax
00047 e8 00 00 00 00  call     ?Number@@YAXJ@Z        ; Number

Мы можем видеть, что сгенерированный код использует MOVSX подписать продлить 16-битное число. Это требуется для Windows ABI.

Когда вы используете #pragma intrinsic(_InterlockedCompareExchange) все немного менее понятно. Я не смог найти однозначного утверждения в документации, касающегося ABI встроенных функций, но мы можем предположить, что оно соответствует Windows ABI, когда речь идет о расширении знака. Компилятор сгенерирует LOCK CMPXCHG инструкция напрямую без вызова функции, но она будет использовать MOVSX когда требуется.

2

Другие решения

_InterlockedCompareExchange это встроенная компилятор как CMPXCHG инструкция. The sign is ignored означает, что когда мы сравниваем 2 целых числа для равный только — без разницы, как мы интерпретируем старший бит — как знаковый бит или нет. это влияет только на сравнение > или же < но не для =, а также 0xffff конечно не равно 0x7fff

0

По вопросам рекламы [email protected]