17

I'm struggling to find pragmatic real-world advice on function naming conventions for a medium sized C library project. My library project is separated into a few modules and submodules with their own headers, and loosely follows an OO style (all functions take a certain struct as first argument, no globals etc). It's laid our something like:

MyLib
  - Foo
    - foo.h
    - foo_internal.h
    - some_foo_action.c
    - another_foo_action.c
    - Baz
      - baz.h
      - some_baz_action.c
  - Bar
    - bar.h
    - bar_internal.h
    - some_bar_action.c

Generally the functions are far too big to (for example) stick some_foo_action and another_foo_action in one foo.c implementation file, make most functions static, and call it a day.

I can deal with stripping my internal ("module private") symbols when building the library to avoid conflicts for my users with their client programs, but the question is how to name symbols in my library? So far I've been doing:

struct MyLibFoo;
void MyLibFooSomeAction(MyLibFoo *foo, ...);

struct MyLibBar;
void MyLibBarAnAction(MyLibBar *bar, ...);

// Submodule
struct MyLibFooBaz;
void MyLibFooBazAnotherAction(MyLibFooBaz *baz, ...);

But I'm ending up with crazy long symbol names (much longer than the examples). If I don't prefix the names with a "fake namespace", modules' internal symbol names all clash.

Note: I don't care about camelcase/Pascal case etc, just the names themselves.

Dan Halliday
  • 273
  • 1
  • 2
  • 6

4 Answers4

12

Prefixing (well, affixing) is really the only option. Some patterns you'll see are <library>_<name> (e.g., OpenGL, ObjC runtime), <module/class>_<name> (e.g. parts of Linux), <library>_<module/class>_<name> (e.g., GTK+). Your scheme is perfectly reasonable.

Long names aren't necessarily bad if they are predictable. The fact that you are ending up with crazy long names and functions that are too big to stick with related functions in a single source file raises different concerns. Do you have some more concrete examples?

user2313838
  • 550
  • 3
  • 8
  • 1
    I see where you're coming from — I have wondered whether I'm being too pedantic about splitting into separate files, but it helps a lot with readability, maintenance and `git merge`ing. As an example I have a module for drawing UI with OpenGL, and I have separate `.c` files for each element that I need (`slider.c`, `indicator.c` etc). These element implementations have a main drawing function maybe a few hundred lines long, and a fair number of `static` helpers within. They also call a few pure geometry functions from within the UI module. Does that sound fairly typical? – Dan Halliday Jun 20 '13 at 15:50
  • A better example of the long names might be my audio module — I have a hierarchy like `Audio Module > Engines > Channels > Filters` which means something like `MyLibAudioEnginesChannel`. Or in my filters submodule: `MyLibAudioFilters` eg. `MyLibAudioFiltersBigSoundingCompressorFloat32Process` – Dan Halliday Jun 20 '13 at 15:58
  • None of that seems unreasonable. A few hundred lines for a function seems a bit long but if what you are drawing is complicated, that can be difficult to avoid. Is it branch heavy or just a lot of instructions? – user2313838 Jun 20 '13 at 16:21
  • Re: the audio module names, you could abbreviate AudioFilters/AudioEngines as I think it would be easy to tell if it's a filter or module based on the name. Datatype qualifiers like Float32 could also be abbreviated (e.g. 'd','f') as such abbreviations are common in C programming. – user2313838 Jun 20 '13 at 16:27
  • 1
    Thanks for your answers — sometimes it feels near impossible to get good info on C program architecture (especially compared to the higher level languages). Many C books I've read barely consider the idea of having multiple modules or even more than one file! Overall, I don't think I'll change much, except considering whether to live with abbreviations for some of the longer names. – Dan Halliday Jun 20 '13 at 17:10
7

The usual convention for C libraries is to use the library name as prefix for externally usable names, e.g.

struct MyLibFoo;
void MyLibAFooAction(...);

For library-internal names that must still be accessible in multiple units of the library, there is no strict convention, but I would use a prefix of the library name and an indication that it is an internal function. For example:

struct MyLibInternalFooBaz;
void MyLibInternalFooBazAction();

I agree that this can lead to names that are quite long and hard to type, but unfortunately that is the price we have to pay for not having a mechanism like C++ namespaces. To reduce the length of the names, at the cost of some clarity, you can opt to use abbreviations in your names, but you have to weigh the advantages and disadvantages carefully.

Bart van Ingen Schenau
  • 71,712
  • 20
  • 110
  • 179
7

What about having a global structure variable prefilled with function pointers?

lib.h

#pragma once

typedef struct
{
    void (*doFoo)(int x);
    const char *(*doBar)(void *p);
} YourApi;

extern const YourApi yourApi;

lib.c:

#include "lib.h"

#include <stdio.h>

static void doFoo(int x)
{
    printf("Doing foo %d\n", x);
}

static const char *doBar(void *p)
{
    printf("Doing bar: %p\n", p);
    return "Hello";
}

const YourApi yourApi = {
    doFoo,
    doBar};

Harness:

#include "lib.h"

int main()
{
    yourApi.doFoo(42);
    yourApi.doBar("asd");
}

The static keyword limits the scope to the translation unit so it won't collide with others.

The user can then shorten it by using a pointer like YourApi *ya = &yourApi, then using ya->doFoo(...).

It also provides a nice way to mock your library for testing.

Calmarius
  • 1,883
  • 2
  • 14
  • 17
  • Cool pattern, it requires a bit of boilerplate, but this will make autocomplete much more useful. – Rick Love Jul 22 '19 at 14:31
  • This pattern looks very interesting to me. The `extern const` in the header file was unexpected. A nice advantage I am seeing here is that the "YourAPI" identifier is the only thing that needs to carefully named, in order to avoid name colisions at the Linking step. – WhyWhat Jun 05 '22 at 12:39
3

If you do want to avoid long prefixes, you can abbreviate library names like what Apple does in iOS and OS X:

  • NSString is a string from the NextStep roots of the OS
  • CALayer is a Core Animation layer
mouviciel
  • 15,473
  • 1
  • 37
  • 64