为啥我不能从 Golang 正确读取 C 常量?

Posted

技术标签:

【中文标题】为啥我不能从 Golang 正确读取 C 常量?【英文标题】:Why can't I read a C constant from Golang properly?为什么我不能从 Golang 正确读取 C 常量? 【发布时间】:2015-04-11 03:01:20 【问题描述】:

我正在使用 go-hdf5 将 hdf5 文件读入 golang。我在 windows7 上使用 mingw 和 hdf5 1.8.14_x86 的最新副本,似乎尝试使用任何预定义类型都行不通,让我们以 T_NATIVE_UINT64 为例。我已将问题简化为以下问题,这基本上使 go-hdf5 脱离了问题,并指出了一些非常根本的问题:

package main

/*
 #cgo CFLAGS: -IC:/HDF_Group/HDF5/1.8.14_x86/include
 #cgo LDFLAGS: -LC:/HDF_Group/HDF5/1.8.14_x86/bin -lhdf5 -lhdf5_hl
 #include "hdf5.h"

 #include <stdio.h>

 void print_the_value2()  printf("the value of the constant is %d\n", H5T_NATIVE_UINT64); 
*/
import "C"

func main() 
    C.print_the_value2()

你显然需要 hdf5 并将编译器指向 headers/dlls 并运行 go get,然后在我的电脑上执行打印它

the value of the constant is -1962924545

上面的运行变体,在读取常量的方式/位置方面,将对 H5T_NATIVE_UINT64 的值给出不同的答案。但是,我很确定这不是正确的值,实际上尝试使用返回 id 的类型是行不通的,这不足为奇。

如果我编写并运行一个“真正的”C 程序,我会得到不同的结果

#include <stdio.h>
#include "hdf5.h"

hid_t _go_hdf5_H5T_NATIVE_UINT64()  return H5T_NATIVE_UINT64; 

int main()

    printf("the value of the constant is %d", _go_hdf5_H5T_NATIVE_UINT64());

编译使用

C:\Temp>gcc -IC:/HDF_Group/HDF5/1.8.14_x86/include -LC:/HDF_Group/HDF5/1.8.14_x86/bin -lhdf5 -lhdf5_hl -o stuff.exe stuff.c

跑步给了我

the value of the constant is 50331683

这似乎是正确的值,因为我可以直接从我的 go 程序中使用它。显然,我希望能够改用常量。知道为什么会发生这种情况吗?

以下cmets的额外信息:

我在hdf5头文件中查找了H5T_NATIVE_UINT64的定义,看到如下

c:\HDF_Group\HDF5\1.8.14_x86\include>grep H5T_NATIVE_UINT64 *
H5Tpkg.h:H5_DLLVAR size_t H5T_NATIVE_UINT64_ALIGN_g; 
H5Tpublic.h:#define H5T_NATIVE_UINT64 (H5OPEN H5T_NATIVE_UINT64_g)
H5Tpublic.h:H5_DLLVAR hid_t H5T_NATIVE_UINT64_g;

整个标题都在这里

http://www.hdfgroup.org/ftp/HDF5/prev-releases/hdf5-1.8.14/src/unpacked/src/H5Tpublic.h

谢谢!

【问题讨论】:

你能告诉我常量 H5T_NATIVE_UINT64 是如何定义的吗? 查看标题,我得到了这个c:\HDF_Group\HDF5\1.8.14_x86\include&gt;grep H5T_NATIVE_UINT64 * H5Tpkg.h:H5_DLLVAR size_t H5T_NATIVE_UINT64_ALIGN_g; H5Tpublic.h:#define H5T_NATIVE_UINT64 (H5OPEN H5T_NATIVE_UINT64_g) H5Tpublic.h:H5_DLLVAR hid_t H5T_NATIVE_UINT64_g; 您的评论难以阅读。您介意将此信息添加到您的问题中吗?它下面有一个“编辑”按钮。请添加尽可能多的信息,包括所有类型和相关的宏定义。 好的,很抱歉 仅供参考,在 Linux 上对此进行了测试,但没有出现问题。打印50331683。在处理无符号整数时,还要确保使用%u 而不是%d。看看生成的代码会很好。使用go build -work 获取位置。 【参考方案1】:

H5T_NATIVE_UINT64 不是一个常数,而是一个 #define,最终计算结果为 (H5Open(), H5T_NATIVE_UINT64_g),cgo 无法理解。

在 gcc 的预处理器上打开调试输出很容易检查:

gcc -E -dM your_test_c_file.c | grep H5T_NATIVE_UINT64

结果:

#define H5T_NATIVE_UINT64 (H5OPEN H5T_NATIVE_UINT64_g)

现在 H5OPEN 也一样:

gcc -E -dM test_go.c | grep '#define H5OPEN'

给予:

#define H5OPEN H5open(),

现在,cgo 确实理解简单的整数常量定义,如#define VALUE 1234,或者 gcc 预处理器将转换为整数常量的任何内容。请参阅$GOROOT/src/cmd/cgo/gcc.go 中的函数func (p *Package) guessKinds(f *File)

【讨论】:

那么为什么它似乎可以在 Linux 上运行呢?或者不是吗?这是否意味着使用 golang 中的 hdf5 注定要失败? cgo 无法在 any 平台上评估非常数 #defines。从 Go 中使用 hdf5 并非注定,您只需要找到/编写一个 Go 包装器,它确实提供了一个正确的 Go 风格 API,没有有趣的 #defines。你也可以试试Swig。顺便说一句,您提到的定义会生成一个函数调用,后跟一个变量......我猜变量值用作#define 应该表示的伪表达式的值。那是什么样的API?您是否查看过编译 hdf5 库时生成的警告数量?我不会用戳棒碰它。 好的,感谢您的意见!好吧,那个包是 go/hdf5 的唯一一个。我想我会坚持使用旧的 csv 文件,直到找到更好的方法。

以上是关于为啥我不能从 Golang 正确读取 C 常量?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 c++ ifstream 不能从设备读取?

golang 常量

为啥我不能使用常量而不是 this.item.number?

为啥我不能将常量数组作为参数传递?

在 Golang 中无法从 Minecraft 正确读取数据包

为啥协议缓冲区 C++ 库不能正确读取二进制对象