如何在C中将一个32位有符号整数值转换为64位有符号整数等价值

5

我有一个编译成使用32位有符号整数的库。当其他应用程序使用标志例如:-DODBC64 进行编译时,它将我在库中使用的相同类型提升为64位有符号整数。

 #ifdef ODBC64
       typedef sint64 SLEN;
 #else
       #define SLEN int
 #endif

当应用程序将引用传递给我的库时:
SLEN count;
mylibraryfunction(&count);

应用程序收到的值看起来像这样:
sizeof(SLEN) = 8
sizeof(SLEN) in my library = 4
m_AffectedRows BEFORE = 0x3030303030303030
m_AffectedRows AFTER = 0x3030303000000000        0

您可以看到,我的库中的赋值操作正在复制4个字节(值为0)。 我需要知道一种将上4个字节重置为0的方法。 例如:

0x0000000000000000

我尝试了静态转换和重新解释转换,但都没有帮助。


1
非常关键。你通过地址传递了一个64位的int到一个函数中,该函数将其解释为32位的int并相信它的声明。这样做是可行的,因为链接器无法识别相同名称符号的不同类型,并可能在没有任何警告的情况下进行链接,但这仍然是错误的。 - Scheff's Cat
听起来确实很危险。有没有理由在一侧使用32位,而在另一侧使用64位?如果是这样的话,我建议为每个函数编写一个小包装器,它只做类型转换(并且可能检查溢出)。 - chtz
那我需要提供两个不同版本的库,一个是针对8字节使用的,另一个是针对4字节使用的,以便应用程序可以链接使用。 - Saba Kauser
我不清楚为什么你需要不同的int大小。你是为x86-32和x86-64编译,还是32位版本节省了大量内存? - chtz
2
这就是为什么我们应该使用stdint.h类型,而不是一些本地车库标准的原因... - Lundin
2个回答

1

我制作了一个MCVE,类似于OP案例中发生的情况。

我甚至不需要额外的库,只需要两个翻译单元(生成两个目标文件)。

首先是lib.cc

#include <cstdint>

extern "C" void func(int32_t *pValue);

void func(std::int32_t *pValue)
{
  *pValue = 0;
}

第二个程序文件 prog.cc:

#include <iostream>
#include <iomanip>

// how prog.cc "knows" func():
extern "C" void func(int64_t *pValue);

int main()
{
  int64_t value = 0x0123456789ABCDEFull;
  std::cout << "value before: " << std::hex << value << '\n';
  func(&value);
  std::cout << "value after : " << std::hex << value << '\n';
  return 0;
}

编译器错误吗?不是。每个翻译单元都使用符合规范的func()原型。

链接器错误吗?不是。符号匹配,其他任何问题都超出链接器的视野。

我必须承认我必须使用extern "C"来实现这一点。否则,至少C++名称混淆将阻止正确的链接。(当我意识到这一点时,我将代码改为C语言。)

输出:

value before: 123456789abcdef
value after : 123456700000000

在wandbox上查看实时演示

这非常危险! 任何使用外部符号的操作都应该使用100%兼容的声明。(是的,C和C ++提供了各种方法来自我伤害。)


想象一下,如果lib.cc函数func()在prog.cc传递指向int32_t的指针时写入int64_t,会发生什么情况:越界访问可能会导致更严重的后果。

这是我的一种思考方式。虽然我不能让用户使用不同的对象链接,但我需要一种方法来根据应用程序使用它们的32位和64位变体。我提供的是最简单的形式,但实际用例要求用户链接到库,并且应该能够正确解释类型。 - Saba Kauser
我认为单个库无法处理不同存储的相同名称的解释。因此,我认为两个库是解决方案。 - Saba Kauser
@SabaKauser 在我看来,Lundin在他的评论中已经很清楚地表达了:对于API,使用stdint.h类型似乎更可靠。另外,即使在大多数64位平台上,int也是32位的。此外,库应该始终具有相同的平台。因此,声明应该足够清晰,以防止出现这种问题。 - Scheff's Cat
@SabaKauser 如果你需要高达64位的整数,为什么不使用int64_t呢?这在32位平台上也是支持的。如果在32位平台上使用超过32位的情况下不能使用,运行时检查可以检测到意外的错误用法。 - Scheff's Cat
谢谢。要求是某些驱动程序管理器将所讨论的类型视为32位,而某些则视为64位。因此,该工具应该允许他们链接到我的库的正确版本,因为这个决定需要由开发人员根据他们使用的驱动程序管理器来做出。 - Saba Kauser

0

你的库无法访问前4个字节,但在调用它之前可以这样做。因此,请尝试首先使用0进行初始化:

SLEN count = 0; // initialize with 0's
mylibraryfunction(&count);

1
这并不进行符号扩展。要做到这一点,您可以在调用库函数后分配 count = int(count); - chtz
1
首先,这并没有解决将一个64位的int值作为32位的int值寻址的问题。无论变量如何初始化,这都是错误的。其次,OP正在提供一个库。那个库怎么可能初始化一个在调用该库的客户编写的代码中的变量呢? - Andrew Henle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接