Pokaż funkcję tylko w bibliotece, a nie w API

Nov 29 2020

Piszę bibliotekę C99 która jest rozprowadzana na kilka plików np

// core.h
void my_private_fn();

void API_my_public_fn();
// core.c
#include "core.h"

void my_private_fn() {
    do_something();
}

void API_my_public_fn() {
    do_something_else();
}
// module_a.h
#include "core.h"

void API_useful_thing();
// module_a.c
#include "module_a.h"

void API_useful_thing() {
    my_private_fn();
}

Chcę tylko API_funkcje poprzedzone być widoczny przez program przy użyciu biblioteki, ale również muszą wystawiać my_private_fnna core.hw celu wykorzystania przez module_a.c. Czy w C jest sposób, aby były my_private_fnwidoczne tylko w bibliotece?

Odpowiedzi

3 SergeBallesta Nov 29 2020 at 01:39

Gdyby funkcja miała być widoczna tylko w jednostce kompilacji, w której została zdefiniowana, można by ją zadeklarować static. Ponieważ język C oferuje kilka możliwych zakresów: symbol może mieć tylko 3 zakresy:

  • lokalny dla bloku (blok może być funkcją lub blokiem wewnątrz funkcji)
  • zakres statyczny (deklaracja statyczna poza funkcją): symbol jest widoczny tylko w jednostce kompilacji, w której jest zadeklarowany
  • zasięg globalny (niestatyczna deklaracja poza funkcją): symbol jest widoczny w całym programie.

Możesz co najwyżej ukryć deklarację w prywatnym pliku dołączanym, którego nie zadeklarujesz w oficjalnie udokumentowanym interfejsie API. W ten sposób posłuszni użytkownicy nie powinni go używać. Nie można jednak uniemożliwić użytkownikom umieszczania deklaracji w ich własnym kodzie i używania funkcji.

2 JohnKugelman Nov 29 2020 at 01:35

Umieść je w wewnętrznym pliku nagłówkowym, który jest używany tylko w bibliotece i nie jest rozprowadzany do użytkowników końcowych - powiedzmy core_internal.h.

user3758232 Dec 31 2020 at 00:19

Znalazłem zgrabniejszy sposób na rozplanowanie mojego kodu w oparciu o odpowiedź Serge'a, którą wybrałem, a która ma największą wartość.

Kluczem jest umieszczenie funkcji „prywatnych” w nagłówkach, które są zawarte tylko w plikach C, a nie w plikach nagłówkowych. W ten sposób symbole „prywatne” są dostępne wewnętrznie, ale nie dla rozmówcy zewnętrznego. W pełnym przykładzie:

core.h:

void my_public_fn();

core_priv.h:

void my_private_fn();

core.c:

#include <stdio.h>

#include "core.h"
#include "core_priv.h"

void my_private_fn() {
    printf("Private function called.\n");
}

void my_public_fn() {
    printf("Public function called.\n");
}

module_a.h:

#include "core.h"

void module_a_fn();

module_a.c:

#include "core_priv.h"
#include "module_a.h"

void module_a_fn() {
    my_private_fn();
    my_public_fn();
}

A jeśli chcemy, możemy zgrupować wiele modułów we wspólnym nagłówku biblioteki.

library.h:

#include "module_a.h"
// etc.

W ten sposób program korzystający z biblioteki musi zawierać tylko jeden plik zawierający tylko:

main.c:

#include "library.h"

int main() {
    //my_private_fn(); // This triggers a compile warning.
    my_public_fn();    // I can still reach the "core" public function.
    module_a_fn();     // This calls the "private" function internally.

    return 0;
}

Kompilowanie gcc -Wall *.c -o main.oi wykonywanie wyników ./main.o:

Public function called.
Private function called.
Public function called.