Namespaces in C
Asked Answered
M

11

65

Is there a way to (ab)use the C preprocessor to emulate namespaces in C?

I'm thinking something along these lines:

#define NAMESPACE name_of_ns
some_function() {
    some_other_function();
}

This would get translated to:

name_of_ns_some_function() {
    name_of_ns_some_other_function();
}
Maim answered 23/12, 2008 at 19:27 Comment(0)
M
61

When using namespace prefixes, I normally add macros for the shortened names which can be activated via #define NAMESPACE_SHORT_NAMES before inclusion of the header. A header foobar.h might look like this:

// inclusion guard
#ifndef FOOBAR_H_
#define FOOBAR_H_

// long names
void foobar_some_func(int);
void foobar_other_func();

// short names
#ifdef FOOBAR_SHORT_NAMES
#define some_func(...) foobar_some_func(__VA_ARGS__)
#define other_func(...) foobar_other_func(__VA_ARGS__)
#endif

#endif

If I want to use short names in an including file, I'll do

#define FOOBAR_SHORT_NAMES
#include "foobar.h"

I find this a cleaner and more useful solution than using namespace macros as described by Vinko Vrsalovic (in the comments).

Mikol answered 23/12, 2008 at 21:44 Comment(2)
I like this approach, because it preserves the usual syntax for declaring and calling functions and it also saves me some typing. This might be a matter of personal preference, but I think this is the most readable solution.Maim
I suggest using simpler macros: #define some_func foobar_some_func. This will let short names be used to initialize function pointers.Cacia
C
95

Another alternative would be to declare a struct to hold all your functions, and then define your functions statically. Then you'd only have to worry about name conflicts for the global name struct.

// foo.h
#ifndef FOO_H
#define FOO_H
typedef struct { 
  int (* const bar)(int, char *);
  void (* const baz)(void);
} namespace_struct;
extern namespace_struct const foo;
#endif // FOO_H

// foo.c
#include "foo.h"
static int my_bar(int a, char * s) { /* ... */ }
static void my_baz(void) { /* ... */ }
namespace_struct const foo = { my_bar, my_baz }

// main.c
#include <stdio.h>
#include "foo.h"
int main(void) {
  foo.baz();
  printf("%d", foo.bar(3, "hello"));
  return 0;
}

In the above example, my_bar and my_baz can't be called directly from main.c, only through foo.

If you have a bunch of namespaces that declare functions with the same signatures, then you can standardize your namespace struct for that set, and choose which namespace to use at runtime.

// goo.h
#ifndef GOO_H
#define GOO_H
#include "foo.h"
extern namespace_struct const goo;
#endif // GOO_H

// goo.c
#include "goo.h"
static int my_bar(int a, char * s) { /* ... */ }
static void my_baz(void) { /* ... */ }
namespace_struct const goo = { my_bar, my_baz };

// other_main.c
#include <stdio.h>
#include "foo.h"
#include "goo.h"
int main(int argc, char** argv) {
  namespace_struct const * const xoo = (argc > 1 ? foo : goo);
  xoo->baz();
  printf("%d", xoo->bar(3, "hello"));
  return 0;
}

The multiple definitions of my_bar and my_baz don't conflict, since they're defined statically, but the underlying functions are still accessible through the appropriate namespace struct.

Clippard answered 23/12, 2008 at 20:15 Comment(6)
I wouldn't even call this a hack - you are organizing exposed pieces of functionality using a language feature. +1 for a clean solution!Matthieu
C has initialization with declaration?Troupe
avesus: yup. and, when initialized, any unspecified structure members are initialized to 0.Clippard
it could work but a struct cannot be partially specifiedInterrogation
It's fun to see my own comments here years ago. But now I come with minus-minus. The initialization order of dependent declarations is undefined in such way. The method doesn't work at all for modules.Troupe
@BrianCannard C has modules?Gadson
M
61

When using namespace prefixes, I normally add macros for the shortened names which can be activated via #define NAMESPACE_SHORT_NAMES before inclusion of the header. A header foobar.h might look like this:

// inclusion guard
#ifndef FOOBAR_H_
#define FOOBAR_H_

// long names
void foobar_some_func(int);
void foobar_other_func();

// short names
#ifdef FOOBAR_SHORT_NAMES
#define some_func(...) foobar_some_func(__VA_ARGS__)
#define other_func(...) foobar_other_func(__VA_ARGS__)
#endif

#endif

If I want to use short names in an including file, I'll do

#define FOOBAR_SHORT_NAMES
#include "foobar.h"

I find this a cleaner and more useful solution than using namespace macros as described by Vinko Vrsalovic (in the comments).

Mikol answered 23/12, 2008 at 21:44 Comment(2)
I like this approach, because it preserves the usual syntax for declaring and calling functions and it also saves me some typing. This might be a matter of personal preference, but I think this is the most readable solution.Maim
I suggest using simpler macros: #define some_func foobar_some_func. This will let short names be used to initialize function pointers.Cacia
B
14

You could use the ## operator:

#define FUN_NAME(namespace,name) namespace ## name

and declare functions as:

void FUN_NAME(MyNamespace,HelloWorld)()

Looks pretty awkward though.

Balaklava answered 23/12, 2008 at 19:32 Comment(3)
I think #define NS1(name) Namespace1 ## name and then void NS1(some_func)() would look less weird (and actually force you to think your namespaces through)Vittoria
Yeah, I was thinking of some "context" too. But whatever it is, the idea lies within the ## operator. It's up to the user to adapt it for his/her own needs.Balaklava
Be careful with the concatenation operator is you're using it with other macros. The order of macro-expansion is not strictly defined, and has differed between two compilers that I had to support. Scarily, neither of them was GCC, so I don't even know what it does.Bosket
D
11

I use the struct-based approach, with two refinements: I add substructures to create hierarchical namespaces, and I define some simple macros when I want to simplify namespaces' path.

Let's take a Foobar library as an example.

foobar.h

#ifndef __FOOBAR_H__
#define __FOOBAR_H__

// definition of the namespace's hierarchical structure
struct _foobar_namespace {
    struct {
        void (*print)(char *s);
    } text;
    struct {
        char *(*getDateString)(void);
    } date;
};

// see the foobar.c file
// it must be the only one defining the FOOBAR macro
# ifndef FOOBAR
    // definition of the namespace global variable
    extern struct _foobar_namespace foobar;
# endif // FOOBAR

#endif // __FOOBAR_H__

foobar.c

// the FOOBAR macro is needed to avoid the
// extern foobar variable declaration
#define FOOBAR

#include "foobar.h"
#include "foobar_text.h"
#include "foobar_date.h"

// creation of the namespace global variable
struct _foobar_namespace foobar = {
    .text = {
        .print = foobar_text__print
    },
    .date = {
        .getDateString = foobar_date__getDateString
    }
};

Then, it's possible to use the namespace:

#include "foobar.h"

void main() {
    foobar.text.print("it works");
}

But there is not so much difference between foobar_text__print() and foobar.text.print(). I think the second one is more readable, but it's questionable. So it become really useful by defining some macros to simplify these namespaces:

#include "foobar.h"

#define txt    foobar.text
#define date   foobar.date

void main() {
    char *today = date.getDateString();
    txt.print(today);
}

This kind of hierarchical namespaces is fast to define, easy to understand, and decrease code verbosity.


Just for fun, here are the files for foobar.text code:

foobar_text.h

#ifndef __FOOBAR_TEXT_H__
#define __FOOBAR_TEXT_H__

void foobar_text__print(char *s);

#endif // __FOOBAR_TEXT_H__

foobar_text.c

#include <stdio.h>
#include "foobar_text.h"

void foobar_text__print(char *s) {
    printf("%s\n", s);
}
Dome answered 25/1, 2014 at 20:28 Comment(0)
C
9

I came up with the following scheme :

(header)

// NS_PREFIX controls the prefix of each type and function declared in this
// header, in order to avoid name collision.
#define NS_PREFIX myprefix_

// Makes a string from argument (argument is not macro-expanded).
#define stringify(arg) #arg

// Concatenation that macro-expands its arguments.
#define concat(p1, p2) _concat(p1, p2) // Macro expands the arguments.
#define _concat(p1, p2) p1 ## p2       // Do the actual concatenation.

// Append the namespace prefix to the identifier.
#define ns(iden) concat(NS_PREFIX, iden)

// header content, for instance :
void ns(my_function)(int arg1, ns(t) arg2, int arg3);

// Allow implementation files to use namespacing features, else
// hide them from the including files.
#ifndef _IMPL
#undef NS_PREFIX
#undef ns
#undef stringify
#undef concat
#undef _concat
#endif // _IMPL

(implementation)

#define  _IMPL 
#include "header.h"
#undef   __IMPL
Cacography answered 10/3, 2011 at 22:30 Comment(0)
P
5

I wrote up a tutorial on how to get the advantage of namespaces and/or templates using C.

Namespaces and templates in C

Namespaces and templates in C (using Linked Lists)

For the basic namespace, one can simply prefix the namespace name as a convention.

namespace MY_OBJECT {
  struct HANDLE;
  HANDLE *init();
  void destroy(HANDLE * & h);

  void do_something(HANDLE *h, ... );
}

can be written as

struct MY_OBJECT_HANDLE;
struct MY_OBJECT_HANDLE *my_object_init();
void my_object_destroy( MY_OBJECT_HANDLE * & h );

void my_object_do_something(MY_OBJECT_HANDLE *h, ... );

A second approach that I have needed that uses the concept of namespacing and templates is to use the macro concatenation and include. For example, I can create a

template<T> T multiply<T>( T x, T y ) { return x*y }

using template files as follows

multiply-template.h

_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);

multiply-template.c

_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
  return x*y;
}

We can now define int_multiply as follows. In this example, I'll create a int_multiply.h/.c file.

int_multiply.h

#ifndef _INT_MULTIPLY_H
#define _INT_MULTIPLY_H

#ifdef _multiply_
#undef _multiply_
#endif
#define _multiply_(NAME) int ## _ ## NAME 

#ifdef _multiply_type_
#undef _multiply_type_
#endif
#define _multiply_type_ int 

#include "multiply-template.h" 
#endif

int_multiply.c

#include "int_multiply.h"
#include "multiply-template.c"

At the end of all of this, you will have a function and header file for.

int int_multiply( int x, int y ) { return x * y }

I created a much more detailed tutorial on the links provided. Hopefully this helps someone!

Parakeet answered 29/12, 2017 at 22:27 Comment(1)
This is interesting. The links are broken though. Have you moved the pages elsewhere? Thanks.Hepner
C
4

An approach similar to the accepted answer is the following:

// inclusion guard
#ifndef FOOBAR_H_
#define FOOBAR_H_

// long names
void foobar_some_func(int);
void foobar_other_func();

// qualified names
#ifdef FOOBAR_SHORT_NAMES
extern struct _foobar {
     void (*some_func)(int);
     void (*other_func)();
} foobar;
#endif

#endif

this header file shall come with a .c file:

#include "foobar.h"
struct _foobar foobar = {
    foobar_some_func;
    foobar_other_func;
};

when using the functions,

foobar.some_func(10);
foobar.other_func();
Congruent answered 30/4, 2013 at 3:54 Comment(1)
Nice this smells like cpp. Why not move the declaration of long names to the C-file?Hurds
A
1

You can use a helper #define macro:

#include <stdio.h>

#define ns(x) gargantua_ ## x

struct ns(stats) {
    int size;
};

int ns(get_size)(struct ns(stats) *st) {
    return st->size;
}

void ns(set_size)(struct ns(stats) *st, int sz) {
    st->size = sz;
}

int main(void) {
    struct ns(stats) stats = {0};

    ns(set_size)(&stats, 3);
    printf("size=%d\n", ns(get_size)(&stats));
    return 0;
}

Running it through the preprocessor gives you:

struct gargantua_stats {
    int size;
};

int gargantua_get_size(struct gargantua_stats *st) {
    return st->size;
}

void gargantua_set_size(struct gargantua_stats *st, int sz) {
    st->size = sz;
}

int main(void) {
    struct gargantua_stats stats = {0};

    gargantua_set_size(&stats, 3);
    printf("size=%d\n", gargantua_get_size(&stats));
    return 0;
}
Actinomycin answered 2/6, 2020 at 22:19 Comment(0)
L
1

One can use prefixes for file function names, like in stb single-file public domain libraries for C/C++: "as a moderately sane way of namespacing the filenames and source function name".

Examples:

  • stb_image_write.h ( file name )
  • STBI_THREAD_LOCAL ( name )
  • static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
Ludlow answered 1/11, 2022 at 13:53 Comment(1)
I wonder why people avoid this simple solution in favor of wanting a . instead of an _Gadson
P
0

here is an example that builds off above approaches and combines them for both funcs and structures to create pseudo-namespaces NAMESPACE1 and NAMESPACE2. the benefit of this over having a structure that holds functions is that the structure-holding-functions approach requires a standardized structure across multiple pseudo-namespaces, and this is not always possible (either at all, or without a lot of work that arguably does not improve the code) or desirable.

Not sure if the macro expansion order could be an issue but this works on GCC and seems to minimize the amount of code changes required, while maintaining decent (though far from ideal) readability.


application.c:

#include <stdio.h>
#include "header1.h"
#include "header2.h"

/* use NAMESPACE1 and NAMESPACE2 macros to choose namespace */

int main() {
  NAMESPACE1(mystruct) data1; // structure specific to this namespace
  NAMESPACE2(mystruct) data2; 

  data1.n1 = '1';
  data1.c  = 'a';
  data2.n2 = '2';
  data2.c  = 'a';

  NAMESPACE1(print_struct)(&data1); // function specific to this namespace
  NAMESPACE2(print_struct)(&data2);

}

header1.h

/* the below block is unnecessary, but gets rid of some compiler warnings */
#ifdef NAMESPACE_REAL
#undef NAMESPACE_REAL
#endif

/* edit the below lines to change the three occurrences of NAMESPACE1 to the desired namespace */
#define NAMESPACE1(name) NAMESPACE1 ## _ ## name
#define NAMESPACE_REAL(name) NAMESPACE1(name)


/* don't edit the next block */
#define TYPEDEF(name, ...) typedef struct NAMESPACE_REAL(name) { __VA_ARGS__ } NAMESPACE_REAL(name)
#define STRUCT(name) struct NAMESPACE_REAL(name)
#define FUNC(name) NAMESPACE_REAL(name)

/* normal header code, using FUNC and STRUCT macros */
#include <stdio.h>

TYPEDEF(mystruct,
        char n1;
        char c;
        );

void FUNC(print_struct)(STRUCT(mystruct) *data);

/* don't edit the rest */
#undef TYPEDEF

api1.c:

#include "header1.h"

/* normal code, using FUNC and STRUCT macros */
void FUNC(print_struct)(STRUCT(mystruct) *data) {
  printf("this is the struct from namespace1: %c %c\n", data->n1, data->c);
}


/* don't edit the rest */
#undef STRUCT
#undef FUNC
#undef NAMESPACE
#undef NAMESPACE_REAL

Other code in header2.h and api2.c is the same as header1.h and header2.h, modified for namespace "NAMESPACE2"

Poltergeist answered 4/1, 2014 at 21:4 Comment(0)
I
0

I realize that this is an old question (11 years old), but I was trying to accomplish essentially what I think you wanted originally as you have listed above.

I wanted there to be a namespace prepended to my functions. But I wanted the ability to change what that namespace would be. By default I wanted for this example to not have a namespace, but if a naming collision occurred then I wanted the ability to prepend a namespace to all of the functions in my library. (This is slightly backwards compared to C++ where there is a namespace by default and you use using namespace whatever to remove the need to specify the namespace every time.) However, just like C++ if you drop in a using namespace statement and alias your code, you will need to update your calling code. You could write some other macro sequence to auto rename your calls as well, but that is outside the scope of what I think you were looking for.

#include <stdio.h>

#define NAMESPACE(...) test_ //Use this as my prepender

//Where all the magic happens which could be included in a header file.
#ifndef NAMESPACE
//No Namespace by default
#define NAMESPACE(...)
#endif

//Actual replacements
#define NSPREPENDER(...) NSPROCESSING(NAMESPACE(), __VA_ARGS__)
#define NSPROCESSING(...) NSFINALIZE(__VA_ARGS__)
#define NSFINALIZE(a,b) a ## b


//BEGIN ACTUAL PROGRAM
//Prototype
void NSPREPENDER(myprint)();

int main()
{
    test_myprint(); //If NAMESPACE(...) is defined to anything else, this code must change.

    return 0;
}

//Implementation
void NSPREPENDER(myprint)()
{
    puts("Testing");
}

This code will compile only on C99 and up since it is using variadic macros. These macros do a form of recursion which is all done so that we can grab the value out of a macro defined at the top.

Breakdown of all it works:

  • We define that we want our namespace to be.
  • If nothing is defined set a default
  • Do a bunch of calls to bypass and (ab)use preprocessor functionality.
  • Add the NSPREPENDER macro function to each c function so that it can be name mangled.
  • Write code using mangled names since the name will be properly mangled by the time the compiler see it.

This code was tested with clang.

Inquisitive answered 12/12, 2019 at 15:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.