Home > Net >  How to access structs in Unions and point to them in c
How to access structs in Unions and point to them in c

Time:12-23

I have to implement a contructor function in c based upon this struct:

struct Node {
    char name[MAX_NAME_LEN   1];
    NodeType type;
    union {
        struct {
            Entry* entries; // list of directory entries
        } dir;
        struct {
            void* contents; // any binary data of the given length
            int length;
        } file;
    };
};

Now I want to build a constructor function to file, point to the contents and save the length in bytes but somehow I don't know how to do it...

Here is my Attempt: i KNOW that i have to allocate space for this but how do i make this pointer stuff?

Node* new_file(char* name) {
    Node* ptr_file = xmalloc(sizeof(Node));
    ptr_file->name;
    return NULL;
}

CodePudding user response:

  • You need to typedef struct { ... } Node for your code to compile.
  • When using anonymous structs/unions you simply don't give a name for the anonymous member. ptr_file->dir.entries or ptr_file->file.contents.
  • Should you ditch the internal struct names and make those anonymous as well you would only need to type ptr_file->entries;.

Please note that anonymous structs/unions were added to the C language in the ISO 9899:2011 version of the language, so you need to use a fairly modern compiler to use them.

As a side note, the void* probably doesn't make any sense. What I think that you are trying to do is this:

#include <stdint.h>

typedef struct {
    char name[MAX_NAME_LEN   1];
    NodeType type;
    union {
        struct {
            Entry* entries; // list of directory entries
        };
        struct {
            uint8_t contents [sizeof(Entry)]; // use to inspect raw data
            int length; // probably not needed
        };
    };
} Node;

CodePudding user response:

With Node* new_file(char* name), Node is not yet defined. Code needs typedef struct Node Node; or the like.

A big challenge to this task is the many potential errors that could creep in: file name too long, memory allocation failure, fopen open failure, read failure, file too long, ...

int length; should be size_t length; as files may be longer than INT_MAX, yet fit in an allocation.

new_file(char* name) looks like it should read a file. Let's make a helper function as there are various degrees of robustness needed. The below commonly "works" yet is technical UB (seeking to the end of a binary file). Adjust as needed.

Illustrative, untested code:

// The below does _not_ return a null character appended string,
// just the data in the file. 
void *alloc_file(const char *file_name, size_t *size) {
  *size = 0;
  FILE *binary_stream = fopen(file_name, "rb");
  if (binary_stream == NULL) {
    return NULL;
  }
  
  long offset = fseek(binary_stream, SEEK_END);
  rewind(binary_stream);
  if (offset == -1 || (unsigned long) offset > SIZE_MAX) {
    fclose(binary_stream);  // Trouble or file too long
    return NULL;
  }
  size_t file_size = (size_t) offset;
  void *buf = malloc(file_size) {
    fclose(binary_stream);
    return NULL;
  }
  if (fread(buf, 1, file_size, binary_stream) != file_szie) {
    fclose(binary_stream);
    free(buf);
    return NULL;
  }
  *size = file_size;
  fclose(binary_stream);
  return buf;
}

Now new_file is easier.

// Better as: Node* new_file(const char* name)
Node* new_file(char* name) {
  if (strlen(name) >= MAX_NAME_LEN) {
    return NULL // name too long
  }      
  // Allocate to the size of the referenced object, not type.
  Node* ptr_file = malloc(sizeof ptr_file[0]);
  if (ptr_file == NULL) {
    return NULL;
  }
  strcpy(ptr_file->name, name);
  ptr_file->type = NodeType_file; // Some constant (OP has not shown yet).
  size_t size = 0;
  ptr_file->file.contents = alloc_file(name, &size);
  if (ptr_file->file.contents == NULL || size > INT_MAX) {
    free(ptr_file->file.contents);
    free(ptr_file);
    return NULL;
  }
  ptr_file->length = (int) size;
  return ptr_file;
}
  • Related