Projekt C unikający konfliktów nazw


13

Z trudem znajduję pragmatyczne porady w świecie rzeczywistym dotyczące konwencji nazewnictwa funkcji dla średniej wielkości projektu biblioteki C. Mój projekt biblioteczny jest podzielony na kilka modułów i podmodułów z własnymi nagłówkami i luźno podąża za stylem OO (wszystkie funkcje przyjmują pewną strukturę jako pierwszy argument, brak globałów itp.). Położyliśmy nasze coś takiego:

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

Zasadniczo funkcje są o wiele za duże, aby (na przykład) trzymać some_foo_actioni another_foo_actionw jednym foo.cpliku implementacji ustawić większość funkcji w trybie statycznym i nazwać to dniem.

Mogę poradzić sobie z usuwaniem symboli wewnętrznych („modułu prywatnego”) podczas tworzenia biblioteki, aby uniknąć konfliktów dla moich użytkowników z ich programami klienckimi, ale pytanie brzmi: jak nazwać symbole w mojej bibliotece? Do tej pory robiłem:

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

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

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

Ale kończę na szalonych długich nazwach symboli (znacznie dłuższych niż w przykładach). Jeśli nie poprzedzę tych nazw „fałszywą przestrzenią nazw”, nazwy symboli wewnętrznych modułów będą się kolidować.

Uwaga: nie obchodzi mnie skrzynka na camelcase / Pascal itp., Same nazwy.

Odpowiedzi:


10

Prefiksowanie (cóż, afiksowanie) jest naprawdę jedyną opcją. Niektóre wzorce, które zobaczysz to <library>_<name>(np. Środowisko uruchomieniowe OpenGL, ObjC), <module/class>_<name>(np. Części systemu Linux), <library>_<module/class>_<name>(np. GTK +). Twój plan jest całkowicie uzasadniony.

Długie nazwy niekoniecznie są złe, jeśli można je przewidzieć. Fakt, że kończysz na szalonych długich nazwach i funkcjach, które są zbyt duże, aby trzymać się powiązanych funkcji w jednym pliku źródłowym, budzi różne obawy. Czy masz jakieś konkretne przykłady?


Widzę, skąd pochodzisz - zastanawiałem się, czy nie jestem zbyt pedantyczny, jeśli chodzi o dzielenie na osobne pliki, ale to bardzo pomaga w czytelności, konserwacji i git mergeing. Jako przykład mam moduł do rysowania UI z OpenGL, i mają oddzielne .cpliki dla każdego elementu, który muszę ( slider.c, indicator.cetc). Te implementacje elementów mają główną funkcję rysunkową o długości może kilkuset linii i znaczną liczbę staticpomocników. Wywołują także kilka funkcji czystej geometrii z poziomu modułu interfejsu użytkownika. Czy to brzmi dość typowo?
Dan Halliday,

Lepszym przykładem długich nazw może być mój moduł audio - mam taką hierarchię, Audio Module > Engines > Channels > Filtersco znaczy coś w rodzaju MyLibAudioEngines<EngineName>Channel<ActionName>. Lub w moim podmodule filtrów: MyLibAudioFilters<FilterName><Type><Action>np. MyLibAudioFiltersBigSoundingCompressorFloat32Process
Dan Halliday

Nic z tego nie wydaje się nierozsądne. Kilkaset linii dla funkcji wydaje się nieco długa, ale jeśli rysujesz coś skomplikowanego, trudno tego uniknąć. Czy gałąź jest ciężka, czy tylko dużo instrukcji?
user2313838,

Re: nazwy modułów audio, możesz skrócić AudioFilters / AudioEngines, ponieważ myślę, że łatwo byłoby stwierdzić, czy jest to filtr czy moduł oparty na nazwie. Kwalifikatory typu danych, takie jak Float32, można również skracać (np. „D”, „f”), ponieważ takie skróty są powszechne w programowaniu C.
user2313838,

Dziękuję za odpowiedzi - czasem uzyskanie dobrych informacji o architekturze programu C wydaje się prawie niemożliwe (szczególnie w porównaniu do języków wyższego poziomu). Wiele książek C, które przeczytałem, ledwo rozważa pomysł posiadania wielu modułów lub nawet więcej niż jednego pliku! Ogólnie rzecz biorąc, nie sądzę, że wiele się zmienię, z wyjątkiem rozważania, czy żyć ze skrótami dla niektórych dłuższych nazw.
Dan Halliday,

5

Zwykłą konwencją dla bibliotek C jest użycie nazwy biblioteki jako prefiksu dla nazw używanych zewnętrznie, np

struct MyLibFoo;
void MyLibAFooAction(...);

W przypadku wewnętrznych nazw bibliotek, które muszą być nadal dostępne w wielu jednostkach biblioteki, nie ma ścisłej konwencji, ale użyłbym prefiksu nazwy biblioteki i wskazania, że ​​jest to funkcja wewnętrzna. Na przykład:

struct MyLibInternalFooBaz;
void MyLibInternalFooBazAction();

Zgadzam się, że może to prowadzić do dość długich i trudnych do wpisania nazw, ale niestety taką cenę musimy zapłacić za brak mechanizmu takiego jak przestrzenie nazw C ++. Aby skrócić długość nazwisk, kosztem pewnej przejrzystości, możesz zdecydować się na użycie skrótów w swoich nazwach, ale musisz dokładnie rozważyć zalety i wady.


3

Jeśli chcesz uniknąć długich prefiksów, możesz skrócić nazwy bibliotek, takie jak to, co robi Apple w iOS i OS X:

  • NSString jest łańcuchem z korzeni systemu operacyjnego NextStep
  • CALayer jest warstwą Core Animation

2

A co z globalną zmienną struktury wypełnioną wskaźnikami funkcji?

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};

Uprząż:

#include "lib.h"

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

Statyczne słowo kluczowe ogranicza zakres do jednostki tłumaczącej, więc nie będzie kolidować z innymi.

Użytkownik może następnie skrócić go za pomocą wskaźnika podobnego do YourApi *ya = &yourApi, a następnie za pomocą ya->doFoo(...).

Zapewnia również dobry sposób na wyśmiewanie biblioteki do testowania.


Fajny wzór, wymaga trochę płyty kotłowej, ale dzięki temu autouzupełnianie będzie znacznie bardziej przydatne.
Rick Love
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.