With reference to the Python version of this issue: [https://github.com/Unidata/netcdf4-python/issues/970], I've now recreated the problem in C.
I've run into a problem when using the relatively new functionality of creating a netCDF4 file in memory, then writing the memory to a file on closure of the netCDF file.
It seems that it's not possible to use nested compound types - i.e. a compound type that contains another compound type.
The code below illustrates the problem.
When using the method below an invalid netCDF file is created. Using ncdump on the file results in the error:
ncdump: test_raw_nc.nc: test_raw_nc.nc: NetCDF: HDF error
#include <stdio.h>
#include <netcdf.h>
#include <netcdf_mem.h>
typedef struct Subarray {
char* ncvar;
char* file;
char* format;
int shape;
} Subarray;
typedef struct Partition {
int index;
int location;
struct Subarray subarray;
} Partition;
void check_err(const int stat, const int line, const char *file)
{
if (stat != NC_NOERR) {
(void)fprintf(stderr,"line %d of %s: %s\n", line, file, nc_strerror(stat));
fflush(stderr);
exit(1);
}
}
int main()
{
const char* file_name = "./test_nc4_compound_types_fails.nc";
int ncid, retval;
int Subarray_typid, Partition_typid;
size_t initialsize = 0;
// create the netCDF4 file in memory
retval = nc_create_mem("test", NC_NETCDF4, initialsize, &ncid);
check_err(retval, __LINE__,__FILE__);
// define the first compound type: Subarray
retval = nc_def_compound(ncid, sizeof(Subarray),
"Subarray", &Subarray_typid);
check_err(retval, __LINE__,__FILE__);
// add the struct members to the Subarray compound type
retval = nc_insert_compound(ncid, Subarray_typid, "ncvar",
NC_COMPOUND_OFFSET(Subarray, ncvar),
NC_STRING);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Subarray_typid, "file",
NC_COMPOUND_OFFSET(Subarray, file),
NC_STRING);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Subarray_typid, "format",
NC_COMPOUND_OFFSET(Subarray, format),
NC_STRING);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Subarray_typid, "shape",
NC_COMPOUND_OFFSET(Subarray, shape),
NC_INT);
check_err(retval, __LINE__,__FILE__);
// define the second compound type: Partition
if ((retval = nc_def_compound(ncid, sizeof(Partition),
"Partition", &Partition_typid)))
check_err(retval, __LINE__,__FILE__);
// add the struct members to the Partition compound type
retval = nc_insert_compound(ncid, Partition_typid, "index",
NC_COMPOUND_OFFSET(Partition, index),
NC_INT);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Partition_typid, "location",
NC_COMPOUND_OFFSET(Partition, location),
NC_INT);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Partition_typid, "subarray",
NC_COMPOUND_OFFSET(Partition, subarray),
Subarray_typid);
check_err(retval, __LINE__,__FILE__);
// close the netCDF file in memory and get a pointer to the memory block used
NC_memio file_memio;
retval = nc_close_memio(ncid, &file_memio);
check_err(retval, __LINE__,__FILE__);
// open the file to write out
FILE* fptr = fopen(file_name, "wb");
fwrite(file_memio.memory, 1, file_memio.size, fptr);
// close the file
fclose(fptr);
}
when using the below code, which does not have nested compound types, a valid netCDF file is created.
#include <stdlib.h>
#include <stdio.h>
#include <netcdf.h>
#include <netcdf_mem.h>
typedef struct Subarray {
char* ncvar;
char* file;
char* format;
int shape;
} Subarray;
void check_err(const int stat, const int line, const char *file)
{
if (stat != NC_NOERR) {
(void)fprintf(stderr,"line %d of %s: %s\n", line, file, nc_strerror(stat));
fflush(stderr);
exit(1);
}
}
int main()
{
const char* file_name = "./test_nc4_compound_types_works.nc";
int ncid, retval;
int Subarray_typid;
size_t initialsize = 0;
// create the netCDF4 file in memory
retval = nc_create_mem("test", NC_NETCDF4, initialsize, &ncid);
check_err(retval, __LINE__,__FILE__);
// define the first compound type: Subarray
retval = nc_def_compound(ncid, sizeof(Subarray),
"Subarray", &Subarray_typid);
check_err(retval, __LINE__,__FILE__);
// add the struct members to the Subarray compound type
retval = nc_insert_compound(ncid, Subarray_typid, "ncvar",
NC_COMPOUND_OFFSET(Subarray, ncvar),
NC_STRING);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Subarray_typid, "file",
NC_COMPOUND_OFFSET(Subarray, file),
NC_STRING);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Subarray_typid, "format",
NC_COMPOUND_OFFSET(Subarray, format),
NC_STRING);
check_err(retval, __LINE__,__FILE__);
retval = nc_insert_compound(ncid, Subarray_typid, "shape",
NC_COMPOUND_OFFSET(Subarray, shape),
NC_INT);
check_err(retval, __LINE__,__FILE__);
// close the netCDF file in memory and get a pointer to the memory block used
NC_memio file_memio;
retval = nc_close_memio(ncid, &file_memio);
check_err(retval, __LINE__,__FILE__);
// open the file to write out
FILE* fptr = fopen(file_name, "wb");
fwrite(file_memio.memory, 1, file_memio.size, fptr);
// close the file
fclose(fptr);
}
With reference to the Python version of this issue: [https://github.com/Unidata/netcdf4-python/issues/970], I've now recreated the problem in C.
I've run into a problem when using the relatively new functionality of creating a netCDF4 file in memory, then writing the memory to a file on closure of the netCDF file.
It seems that it's not possible to use nested compound types - i.e. a compound type that contains another compound type.
The code below illustrates the problem.
When using the method below an invalid netCDF file is created. Using ncdump on the file results in the error:
ncdump: test_raw_nc.nc: test_raw_nc.nc: NetCDF: HDF errorwhen using the below code, which does not have nested compound types, a valid netCDF file is created.