Tornar a função visível apenas em uma biblioteca, não na API

Nov 29 2020

Estou escrevendo uma biblioteca C99 que é distribuída entre vários arquivos, por exemplo

// 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();
}

Quero apenas as API_funções prefixadas para ser visível por um programa usando a biblioteca, mas eu também preciso para expor my_private_fnem core.h, a fim de ser usado por module_a.c. Existe uma maneira em C de tornar my_private_fnvisível apenas dentro da biblioteca?

Respostas

3 SergeBallesta Nov 29 2020 at 01:39

Se a função tivesse que ser visível apenas na unidade de compilação onde foi definida, você poderia declará-la static. Porque a linguagem C oferece poucos escopos possíveis: um símbolo pode ter apenas 3 escopos:

  • local para um bloco (o bloco pode ser uma função ou um bloco dentro de uma função)
  • escopo estático (declaração estática fora de uma função): o símbolo só é visível na unidade de compilação onde é declarado
  • escopo global (declaração não estática fora de uma função): o símbolo é visível em todo o programa.

No máximo, você pode ocultar a declaração em um arquivo de inclusão privado que você não declara na API oficial documentada. Dessa forma, usuários obedientes não devem usá-lo. Mas você não pode impedir que os usuários coloquem a declaração em seu próprio código e usem a função.

2 JohnKugelman Nov 29 2020 at 01:35

Coloque-os em um arquivo de cabeçalho interno que é usado apenas dentro da biblioteca e não é distribuído aos usuários finais - digamos core_internal.h,.

user3758232 Dec 31 2020 at 00:19

Eu encontrei uma maneira mais limpa de expor meu código com base na resposta de Serge que selecionei, cujo mérito vai para.

A chave é colocar as funções "privadas" em cabeçalhos que são incluídos apenas em arquivos C, não em arquivos de cabeçalho. Desta forma, os símbolos "privados" estão disponíveis internamente, mas não para um chamador externo. Em um exemplo completo:

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

E se quisermos, podemos agrupar possivelmente vários módulos em um cabeçalho de biblioteca comum.

library.h:

#include "module_a.h"
// etc.

Dessa forma, um programa que usa a biblioteca só precisa incluir um arquivo com apenas:

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

Compilando gcc -Wall *.c -o main.oe executando ./main.orendimentos:

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