C++ 联锁比较交换文档中“符号被忽略”的含义
每个参数的文档都是如此 该标志被忽略 那么,这是否意味着像16位版本的0xffff和0x7fff这样的数字将被其他宽度内部函数的_InterlocatedCompareeExchange16等视为相等?或者这是否意味着内部函数同时接受有符号整数和无符号整数?还是别的什么C++ 联锁比较交换文档中“符号被忽略”的含义,c++,winapi,visual-c++,intrinsics,interlocked,C++,Winapi,Visual C++,Intrinsics,Interlocked,每个参数的文档都是如此 该标志被忽略 那么,这是否意味着像16位版本的0xffff和0x7fff这样的数字将被其他宽度内部函数的_InterlocatedCompareeExchange16等视为相等?或者这是否意味着内部函数同时接受有符号整数和无符号整数?还是别的什么 如果这不是文档中的错误,至少看起来不明确。InterloctedCompareeExchange这是编译器内部实现的CMPXCHG指令。符号被忽略意味着,当我们比较2个整数时,如果只比较相等的值,那么我们解释高位的方式就没有什么
如果这不是文档中的错误,至少看起来不明确。InterloctedCompareeExchange这是编译器内部实现的CMPXCHG指令。符号被忽略意味着,当我们比较2个整数时,如果只比较相等的值,那么我们解释高位的方式就没有什么不同,即符号位或否。这只影响了>或的比较符号位不被忽略,它与其他位一样进行比较 比较交换。。函数只关心位的相等性,不以任何特殊方式解释它们。在基于x86的系统上,它们是用/CMPXCHG8B指令实现的,它将CPU寄存器与内存位置进行比较。符号问题变成了关于类型和参数传递的问题,而不是比较本身 因为大多数互锁函数也作为Windows API函数存在,所以我们可以先看看这些函数。采用长类型的32位参数。较小的有符号类型将符号扩展到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_interlockedcarpeexchange时,事情就不那么清楚了。我在文档中找不到关于内在函数ABI的明确声明,但我们可以假设它在签名扩展时遵循Windows ABI。编译器将在不调用函数的情况下直接生成LOCK CMPXCHG指令,但在需要时将使用MOVSX。这意味着接受有符号和无符号整数-因为只比较相等的整数,而不比较较小或较大的整数-无差异有符号或无符号文档在类型有符号时看起来不正确或至少不明确类型,所以它可能不相关,方法根本没有提到这一点。我会和你一起提出这个问题MS@EdChum,我已经在那个页面上提交了反馈。当有显式方法(如32位和64位版本)时,我很少使用intrinsic,所以我很惊讶它竟然会这样说。我的理解是,说明这一点毫无意义,特别是当它使用有符号类型时,它仍然可以使用有符号和无符号类型。我的期望是,任何像样的std::atomic实现都会对没有锁的对象使用锁数组,使用对象地址的散列来选择哪个锁。可以像使用低位作为索引一样简单,这样不同的对象将使用不同的锁,而不是对所有对象使用单个全局锁!传递给函数的值的扩展方式仅取决于值类型,而不取决于参数类型。有符号值将是有符号扩展movsx,而无符号值将是零扩展movzx。假设您可以声明NumberLONG val或NumberLONG val,并查看结果将不依赖于参数类型ULONG或LONG。结果将仅取决于值类型:例如Numbersigned char-1;->0xFFFFFF和numberRunSigned字符-1;->0xff。因此,所有这些值的扩展方式完全不取决于_interloctedcompareexchange-这是分离的。如果值类型是有符号的,则作为参数传递的值将进行符号扩展,并将符号扩展到参数类型的大小。参数类型的符号性并不重要,这是正确的。是的,但我确实做到了这一点,并试图在我的评论中说,只是英语不好。因此,作为参数传递的值如何进行符号扩展根本不取决于_interloctedcompareeexchange-这是常见的c/c++规则。因此,情况绝对清楚-在比较中,cmpxchg使用了所有位以及值如何扩展-在所有单独的问题中,您不能这样说,当作为参数传递时,值将如何进行符号扩展而不依赖于_InterlocatedCompareeExchange根本不正确,因为函数签名确实起作用。如果它将被符号扩展取决于值类型,它将被扩展的最小宽度取决于函数参数类型。是的,您可以更正它的宽度,我的意思是它类型参数的声明方式-有符号或无符号。