如何使用H5LTget_attribute_string函数?

How to use the H5LTget_attribute_string function?

我已经在 HDF Forum here 上问过这个问题,但(还)没有收到答复。所以我想我在这里碰碰运气。

我在 Python (h5py) 中创建了一个小测试文件,想使用 H5LTget_attribute_string 函数从中读取属性。但是,我不确定如何使用此功能。

我的测试文件是这样的。

HDF5 "attr.h5" {
GROUP "/" {
   DATASET "my_dataset" {
      DATATYPE  H5T_STD_I64LE
      DATASPACE  SIMPLE { ( 12 ) / ( 12 ) }
      DATA {
      (0): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
      }
      ATTRIBUTE "string_attr" {
         DATATYPE  H5T_STRING {
            STRSIZE H5T_VARIABLE;
            STRPAD H5T_STR_NULLTERM;
            CSET H5T_CSET_UTF8;
            CTYPE H5T_C_S1;
         }
         DATASPACE  SCALAR
         DATA {
         (0): "this is a string"
         }
      }
   }
}
}

看着 documentation of H5LT_GET_ATTRIBUTE 在我看来,我需要分配一个缓冲区并将缓冲区的地址作为最后一个参数传递,之后 H5LT_GET_ATTRIBUTE 函数将填充缓冲区。因此,我的第一次尝试是这样的。

#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"

int main()
{
    herr_t  status;

    hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
    assert(file_id >= 0);
    
    char string[1024];  // assume buffer is large enough;
    
    fprintf(stderr, "string : %s\n", string);
    fprintf(stderr, "pointer: %p\n", string);

    fprintf(stderr, "---- reading attribute ----\n");
    status = H5LTget_attribute_string(file_id, "my_dataset", 
                                      "string_attr", string);
    assert(status >= 0);
    
    fprintf(stderr, "string : %s\n", string);
    fprintf(stderr, "pointer: %p\n", string);
    
    status = H5Fclose(file_id);
    assert(status >= 0);
}

然而这并没有像预期的那样工作,请看下面的输出。

string : 
pointer: 0x7ffe3f7ec770
---- reading attribute ----
string : @B�k2V
pointer: 0x7ffe3f7ec770

经过一些谷歌搜索和试验,我发现最后一个参数应该是缓冲区的地址。然后 H5LT_GET_ATTRIBUTE 函数将使缓冲区指向实际的属性值。以下函数编译时出现警告,但它给出了正确的输出。

#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"

int main()
{
    herr_t  status;

    hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
    assert(file_id >= 0);
    
    char* string = NULL;
    
    fprintf(stderr, "string : %s\n", string);
    fprintf(stderr, "pointer: %p\n", string);

    fprintf(stderr, "---- reading attribute ----\n");
    status = H5LTget_attribute_string(file_id, "my_dataset", 
                                      "string_attr", &string);
    assert(status >= 0);
    
    fprintf(stderr, "string : %s\n", string);
    fprintf(stderr, "pointer: %p\n", string);
    
    status = H5Fclose(file_id);
    assert(status >= 0);
}

输出

string : (null)
pointer: (nil)
---- reading attribute ----
string : this is a string
pointer: 0x559e9e3d1240

现在我非常乐意像这样使用它,我可以转换为 **char 来摆脱警告,但我想确保这是预期的行为。理想情况下,应该更新文档。

所以我的问题是:

  1. 第二个例子是否正确?
  2. string缓冲区的数据有效期是多久?即HDF lib什么时候释放内存? (例如,当文件关闭时)
  3. 在使用之前是否应该使用strcpy复制字符串数据?

我不做 HDF5,但我做的 C 足够多,可以为您提供一些答案,并且非常符合您的要求。

  1. 第二个例子是否正确?

是的。首先是因为它 returns 是正确的预期结果,其次 因为任何将填充字符串(又名:char *)的库都需要您提供指针的地址(又名:char **)。

  1. string缓冲区的数据有效期是多久?

只要你的程序运行就有效。已为您分配了大小合适的内存,因此它在程序的整个生命周期内都有效,但是现在您有责任释放它。 如果您需要更多详细信息,请 respond/comment 在该消息中说明,我们会帮助您。

  1. 在使用之前是否应该使用strcpy复制字符串数据?

不,你没有为你分配内存,你可以保持原样:-)


我建议你做的下一步:

  • 既然您在他们的文档中发现了问题,您应该联系他们并告诉他们。

如 Scot Breitenfeld(来自 HDF 组)pointed

If you are reading a variable length string with H5LTget_attribute_string (H5T_VARIABLE) then you don’t need to allocate the string, just pass in a pointer and the library will handle the allocations. If you are reading a fixed length string then you need to allocate a string that is “large enough”.

所以,(1) 我觉得你的第二种方法没问题。

至于 (2) 和 (3),我敢打赌你负责释放缓冲区,所以不需要复制它。但是,可以肯定的是,您可以使用调试器来检查库是否正在访问缓冲区,或者更好的是,使用 valgrind 来查找内存泄漏(当您尝试不 free 缓冲区时)。