Реализация пространств имён в си
Реализация пространства имён в си с помощью структур
Приведённый ниже материал не относится к основному курсу, но позволяет полнее понять особенности языка си и упростить решение некоторых прикладных задач. Если вы не смогли совладать с основным курсом, остановитесь здесь и не читайте дальше.
Одной из больших проблем си является отсутствие пространств имён или системы модулей. Если есть две библиотеки, в которых функции имеют одинаковые имена, то произойдёт коллизия: нельзя будет понять, какая из функций будет использована. Компоновщик выдаст ошибку, что функция определена более одного раза.
В нашем проекте есть два подключаемых файла
File1.h
#pragma once int doSomething(int, int);
и соответствующий ему .с файл File1.c
#include "File1.h" int doSomething(int a, int b) { return a + b; }
И файл File2.h
#pragma once int doSomething();
и соответствующий ему файл File2.c
#include "File2.h" int doSomething(int a, int b) { return a * b; }
Если мы попытаемся подключить оба заголовочных файла, то получим ошибку: обнаружен многократно определенный символ - один или более.
#include <conio.h> #include <stdio.h> #include "File1.h" #include "File2.h" void main() { }
Избавиться от неё можно (возможно, ещё есть другие способы...) объявив функции doSomething статическими.
#pragma once static int doSomething(int, int);
Теперь проект скомпилируется, только вот использовать эти функции в main не удастся. Для того, чтобы использовать их, создадим структуру
#pragma once #include <stdlib.h> typedef struct FILE1 { int (*doSomething) (int, int); } FILE1; static int doSomething(int a, int b); FILE1* getFile1Namespace(void);
для файла File2.h
#pragma once #include <stdlib.h> typedef struct FILE2 { int (*doSomething) (int, int); } FILE2; static int doSomething(int a, int b); FILE2* getFile2Namespace(void);
Функции getFile?Namespace возвращают структуру, у которой поле - указатель на функцию - равно нашей статической функции.
#include "File1.h" int doSomething(int a, int b) { return a + b; } FILE1* getFile1Namespace() { FILE1 *tmp = (FILE1*) malloc(sizeof(FILE1)); tmp->doSomething = doSomething; return tmp; }
File2.c
#include "File2.h" int doSomething(int a, int b) { return a * b; } FILE2* getFile2Namespace() { FILE2 *tmp = (FILE2*) malloc(sizeof(FILE2)); tmp->doSomething = doSomething; return tmp; }
Теперь в main можно создать экземпляр структуры FILE1 или FILE2 и через поле структуры обратиться к статической функции.
#include <conio.h> #include <stdio.h> #include "File1.h" #include "File2.h" void main() { int a, b; FILE1 *ns1 = getFile1Namespace(); FILE2 *ns2 = getFile2Namespace(); a = 10; b = 20; printf("using namespace 1 = %d\n", ns1->doSomething(a, b)); printf("using namespace 2 = %d\n", ns2->doSomething(a, b)); free(ns1); free(ns2); _getch(); }
