在c#中实现c++中的函数(MAKE_HRESULT - Windows函数)

本文关键字:函数 HRESULT Windows MAKE 实现 c++ | 更新日期: 2023-09-27 18:18:31

我在c++中有这样的代码

#define dppHRESULT(Code) '
    MAKE_HRESULT(1, 138, (Code))
        long x = dppHRESULT(101);

结果为x = -2138439579.

MAKE_HRESULT是一个窗口函数,定义为

#define MAKE_HRESULT(sev,fac,code) '
    ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )

我需要在c#中复制这个。所以我写了这段代码:

  public static long MakeHResult(uint facility, uint errorNo)
        {
            // Make HR
            uint result = (uint)1 << 31;
            result |= (uint)facility << 16;
            result |=  (uint)errorNo;
            return (long) result;
        }

和调用:

    // Should return type be long actually??
    long test = DppUtilities.MakeHResult(138, 101);

但我得到不同的结果,test = 2156527717。

为什么?有人能帮我复制c++函数也在c# ?使我在相似的输入上得到相似的输出?


替代实现。

如果我使用这个实现

  public static long MakeHResult(ulong facility, ulong errorNo)
        {
            // Make HR
            long result = (long)1 << 31;
            result |= (long)facility << 16;
            result |= (long)errorNo;
            return (long) result;
        }

这适用于输入101。但是如果我输入-1,那么c++返回-1作为结果,而c#返回4294967295。为什么?

我真的很感激你的帮助,因为我被卡住了。

在c#中实现c++中的函数(MAKE_HRESULT - Windows函数)

我已经重写了这个函数,使其与c#相同。

static int MakeHResult(uint facility, uint errorNo)
{
    // Make HR
    uint result = 1U << 31;
    result |= facility << 16;
    result |= errorNo;
    return unchecked((int)result);
}

c#对有符号/无符号转换更严格,而原始的C代码没有注意到它。有符号类型和无符号类型混合使用通常会让人头疼。

正如Ben Voigt在他的回答中提到的,这两种语言在类型命名上是不同的。C中的long实际上是c#中的int。它们都指向32位类型。

1U中的U表示"这是一个无符号整数"。(简单提醒一下:有符号类型可以存储负数,无符号类型不能。)这个函数中的所有算术运算都是无符号的,最后的值只是在最后转换为有符号的值。这是最接近原始C宏的方法。

unchecked在这里是必需的,否则c#将不允许您转换值,如果它超出了目标类型的范围,即使位是相同的。如果您不介意在处理负数时值不同,则在有符号和无符号之间切换通常需要此操作。

在Windows c++编译器中,long是32位的。在c#中,long是64位。这段代码的c#转换不应该包含类型关键字long

SaxxonPike提供了正确的翻译,但他的解释遗漏了这一重要信息。

中间结果是一个32位无符号整数。在c++版本中,强制转换为带符号的32位值,导致高位被重新解释为符号位。SaxxonPike的代码也做到了这一点。如果中间值设置了最高有效位,则结果为负。

在问题的原始代码中,强制转换为64位带符号的版本,它保留旧的高位作为正常的二进制数字,并添加一个新的符号位(始终为零)。因此,结果总是肯定的。即使低32位完全匹配c++中的32位结果,在返回long的c#版本中,c++中的符号位不被视为符号位。

在问题的新尝试中,发生了同样的事情(64位数字中的符号位始终为零),但它发生在中间计算而不是最后。

您正在unsigned类型(uint)中计算它。所以位移会有相应的表现。试着用int代替,看看会发生什么。

这里的线索是,作为无符号整型的2156527717与作为有符号整型的-2138439579相同。它们实际上是相同的位。