Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Using if directives in headers

I have a working generic graph. The type for vertex is currently defined as:

typedef struct vertex {
  void *data;
  char *label;
  bool inGraph;
} vertex;

The void pointer can then be customized for any algorithm, like BFS, DFS, etc. This works, but I want to simplify the code by using a separate header file for a vertex that specifies its type as needed, and is included in graph.h. Something like this:

#ifndef VERTEX_H_INCLUDED
#define VERTEX_H_INCLUDED

#include <stdlib.h>
#include <stdbool.h>

#if defined (GRAPH_VERTEX1)
typedef struct vertex {
  struct vertex *parent;      
  char *label;        
  bool inGraph;       
} vertex;

#elif defined (GRAPH_VERTEX2)
typedef struct vertex {
  size_t dist;    
  char *label;        
  bool inGraph;       
} vertex;

#else  // default
typedef struct vertex {   
  char *label;        
  bool inGraph;       
} vertex;

#endif

#endif

This does not work, however. The right vertex type is not selected and allocated.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I have made an example to reproduce the issue.

main.c

#include <stdio.h>

#define GRAPH_VERTEX1

#include "graph.h"

int main() {
  vertex *v = createVertex("test");
  v->inGraph = true;
  vertex *parent = createVertex("parent");

  printf("Vertex: %s\n", v->label);
  printf("Parent: %s\n", parent->label);
  printf("In graph: %d\n", parent->inGraph);

  freeVertex(v);
  freeVertex(parent);
  return 0;
}

graph.h

#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED

#include <stdlib.h>

#include "vertex.h"


vertex *createVertex(char *label);

void freeVertex(vertex *v);


#endif

graph.c

#include "graph.h"
#include <string.h>

vertex *createVertex(char *label) {
  vertex *v = calloc(1, sizeof(vertex));
  v->label = calloc(strlen(label) + 1, sizeof(char));
  v->inGraph = false;
  strcpy(v->label, label);
  return v;
}

void freeVertex(vertex *v) {
  free(v->label);
  free(v);
}

The example works fine if I put a single definition in vertex.h. However, if I try to use the if directives, I get the following errors:

==986== Memcheck, a memory error detector
==986== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==986== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==986== Command: ./a.out
==986==
==986== Invalid write of size 1
==986==    at 0x1090FD: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==  Address 0x4a8e050 is 0 bytes after a block of size 16 alloc'd
==986==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==986==    by 0x109279: createVertex (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)       
==986==    by 0x1090F5: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==
==986== Invalid read of size 1
==986==    at 0x10913A: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==  Address 0x4a8e0f0 is 0 bytes after a block of size 16 alloc'd
==986==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==986==    by 0x109279: createVertex (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)       
==986==    by 0x109108: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==
Vertex: (null)
Parent: (null)
In graph: 0
==986== 
==986== HEAP SUMMARY:
==986==     in use at exit: 0 bytes in 0 blocks
==986==   total heap usage: 5 allocs, 5 frees, 4,140 bytes allocated
==986==
==986== All heap blocks were freed -- no leaks are possible
==986==
==986== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==986==
==986== 1 errors in context 1 of 2:
==986== Invalid read of size 1
==986==    at 0x10913A: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==  Address 0x4a8e0f0 is 0 bytes after a block of size 16 alloc'd
==986==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==986==    by 0x109279: createVertex (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)       
==986==    by 0x109108: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==
==986==
==986== 1 errors in context 2 of 2:
==986== Invalid write of size 1
==986==    at 0x1090FD: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==  Address 0x4a8e050 is 0 bytes after a block of size 16 alloc'd
==986==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==986==    by 0x109279: createVertex (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)       
==986==    by 0x1090F5: main (in /mnt/d/Dropbox/Programs/pubgithub/CLRS/datastructures/graphs/dgraph/a.out)
==986==
==986== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

>Solution :

graph.c needs to have the same #define GRAPH_VERTEX1 as you have in main.c – otherwise that translation unit will get the default vertex definition (since neither GRAPH_VERTEX1 nor GRAPH_VERTEX2 will be defined).

You could put #define GRAPH_VERTEX1 in a separate header file that you include from both main.c and graph.c:

#ifndef SOMENAME_H
#define SOMENAME_H

#define GRAPH_VERTEX1
#include "graph.h"

#endif

… or just put it at the top of graph.h.

Alternatively, tell your compiler to define it from the command line. Example:

gcc -DGRAPH_VERTEX1 ...
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading