Skip to content

Cannot create nested compound types when creating netCDF file in memory  #1489

@nmassey001

Description

@nmassey001

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);
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions