1

The definition of struct datatype should be in the header file and not the opposite. This is what I understand while this project does the opposite in this special case. What drive the contributor to decide to do so and why ? I am aware it is a design decision but shall I submit a direct question to the code contributor? I was looking at the GNU masscan project and came to my attention the two file event-timeout.c which has the definition of a struct datatype

struct Timeouts {
    /**
     * This index is a monotonically increasing number, modulus the mask.
     * Every time we check timeouts, we simply move it foreward in time.
     */
    uint64_t current_index;

    /**
     * The number of slots is a power-of-2, so the mask is just this
     * number minus 1
     */
    unsigned mask;

    /**
     * The ring of entries.
     */
    struct TimeoutEntry *slots[1024*1024];
};

while in the header file event-timeout.h contains the below statement to import the "Timeouts" struct datatype

struct Timeouts;
struct Timeouts *timeouts_create(uint64_t timestamp_now);

I am not sure why the struct Timeouts is not defined in the header file ?

  • 3
    It hides the implementation from modules that don't need to see it. – dbush Feb 10 '23 at 21:05
  • 3
    It makes `Timeouts` an [*opaque data type*](https://en.wikipedia.org/wiki/Opaque_data_type). It's a common way to implement OOP-like data hiding in C. – Some programmer dude Feb 10 '23 at 21:08
  • So in fact, it's not much like an "import" at all, especially if you're using that term in a pythonic sense. `struct Timeouts;` is simply a forward declaration announcing that such a type exists. Absent an accompanying definition, nothing can be done directly with objects of that type. Pointers to that type, on the other hand, are a different question. – John Bollinger Feb 10 '23 at 21:22
  • @Someprogrammerdude make sense. Can you please give an example below so that I an mark your answer as correct if possible. – amed svensson Feb 10 '23 at 21:32
  • @dbush thanks Yes it comes under the category of Opaque data type as suggested by the link given by "Some programmer dude". Thanks . – amed svensson Feb 10 '23 at 21:34
  • It is also the result of `struct` in C and C++ being very different things. In C a struct is simply an object that allows for the collection of differing data types. In C++ a struct is simply a class with all members defaulting to public access. C struct and C++ class are very different things and implementation preferences are different. – David C. Rankin Feb 11 '23 at 06:22

1 Answers1

0
  1. C encourages interface and type declarations to placed in header files, and implementation the .c files. A struct may leak implementation details that you prefer to hide (to makes changes easier or even possible). You do that by only exposing a forward declaration of your struct optionally as a typedef struct or typedef struct * and functions to allocate and free an instance of the object (forcing heap allocation):
#ifndef FOO_H
#define FOO_H

typedef struct foo foo;
foo *foo_create();
void foo_bar(foo *f, bar *none);
foo_destroy(foo *f);

#endif

This improves incremental build time. In particular a small exposed implementation detail (that merely change the size of a struct) may have ripple effect that result in a large part of an entire code base having to be recompiled. Btw, Michael Feathers: "Effectively with Legacy Code", while dated, is a really interesting book on this subject.

  1. To link against code without having the source for the definitions. We do this all the time with libraries.

  2. Variables can only be declared once so you need to make to make them extern in a header file, and then most likely link the declaration once.

Allan Wind
  • 23,068
  • 5
  • 28
  • 38