C - deklarace metod ve stukturách s definicí bokem

.

C - deklarace metod ve stukturách s definicí bokem
« kdy: 29. 04. 2017, 21:24:04 »
Mejme tento priklad:
Kód: [Vybrat]
/* interface.h */

struct library {
    const int some_value;
    void (*function1)(void);
    void (*method2)(int);
    /* ... */
};

extern const struct library Library;
/* interface.h */

/* interface.c */
#include "interface.h"

void method1(void)
{
   ...
}
void method2(int arg)
{
   ...
}

const struct library Library = {
    .method1 = method1,
    .method2 = method2,
    .some_value = 36
};
/* end interface.c */

/* client code */
#include "interface.h"

int main(void)
{
    Library.method1();
    Library.method2(5);
    printf("%d\n", Library.some_value);
    return 0;
}
/* end */
http://stackoverflow.com/questions/4396140/why-doesnt-ansi-c-have-namespaces


Neuměli byste ho pls někdo upravit tak, aby Library nebyl v podstatě singleton, ale muzu ho pouzivat v podstate jako typ? Chtěl bych nicméně, aby bylo zachováno to, že metody si deklaruji v .h, ale definuji a rovnez i pripojim k funkcnim pointrum v .c .

Diky
« Poslední změna: 01. 05. 2017, 21:14:17 od Petr Krčmář »



ddffdff

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #2 kdy: 29. 04. 2017, 22:50:38 »
Lidi vymysleji strasne picoviny a to mi vadi napr. na c++ a naopak se mi libi, ze to v go opousteji. Nezavadejte si to do c.

Kdyz je library const, tak ji nechcete uz menit. Nedelejte ji const a muzete ji menit hodnoty kdekoliv.

Staci si udelat funkci init, neco jako konstruktor pro tu strukturu a muzete ji pouzivat milionkrat, delat konkretni instanci library a omezovat se na ni jako na singleton je designerska chyba.

Peťa

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #3 kdy: 29. 04. 2017, 23:33:27 »
Lidi vymysleji strasne picoviny a to mi vadi napr. na c++ a naopak se mi libi, ze to v go opousteji. Nezavadejte si to do c.

Kdyz je library const, tak ji nechcete uz menit. Nedelejte ji const a muzete ji menit hodnoty kdekoliv.

Staci si udelat funkci init, neco jako konstruktor pro tu strukturu a muzete ji pouzivat milionkrat, delat konkretni instanci library a omezovat se na ni jako na singleton je designerska chyba.

Určitě jste pochopil, o co v tom příkladu jde? Pointa totiž je, vystavit API, použít strukturu jakožto namespace (které v c nejsou) a skrýt implementační detaily těch metod, aby se jim následně nemusely dělat ty hrozně dlouhé c-like názvy, protože by jinak mohlo dojít k duplicitám. Proto musí být ty metody ve struktuře a aby to api šlo používat out of box, inicializace te struktury proběhne v .c soboru.

Funkci init si rozhodně neuděláte, protože jak už jsem řekl, v C nejsou ty namespacy, takže je vysoká pravděpodobnost, že ta funkce init() už bude použitá někde jinde  :D :D :D :D


Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #4 kdy: 30. 04. 2017, 03:12:27 »
A nebo použít C++. Můj život má limitovaný čas.


ddffdff

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #5 kdy: 30. 04. 2017, 05:30:33 »
V c namespace neni a je zbytecne to tam zavadet.
V libce muze byt xy ruznych metod, a je na me, abych
Si do struktury nastavil takove metody a hodnoty, ktere chci.

Neviditelný

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #6 kdy: 30. 04. 2017, 10:23:53 »
Něco takového?

mylibrary.h
Kód: [Vybrat]
#ifndef MYLIBRARY_H
#define MYLIBRARY_H

struct Context;

typedef struct {
void (*funcOne)(void);
void (*funcTwo)(const struct Context *);

struct Context *ctx;
} Library;

typedef struct {
const Library * (*initialize)(const int);
void (*deinitialize)(const Library *);
} LibraryInitializer;

extern const LibraryInitializer libraryInit;

#endif // MYLIBRARY_H

mylibrary.c
Kód: [Vybrat]
#include "mylibrary.h"
#include <stdio.h>
#include <stdlib.h>

struct Context {
int n;
};

void funcOne_v1(void)
{
printf("f v1 called\n");
}

void funcOne_v2(void)
{
printf("f v2 called\n");
}

void funcTwo(const struct Context *ctx)
{
printf("n * 2 = %d\n", ctx->n * 2);
}

const Library * initialize(const int n)
{
Library *library = malloc(sizeof(Library));
if (!library)
return NULL;

struct Context *ctx = malloc(sizeof(struct Context));
if (!ctx)
return NULL;
ctx->n = n;

if (n > 1)
library->funcOne = funcOne_v2;
else
library->funcOne = funcOne_v1;

library->funcTwo = funcTwo;

library->ctx = ctx;

return library;
}

void deinitialize(const Library *library)
{
free(library->ctx);
free((Library *)library);
}

const LibraryInitializer libraryInit = {
initialize,
deinitialize
};

test.c
Kód: [Vybrat]
#include "mylibrary.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
const Library *libInstanceOne = libraryInit.initialize(65);
const Library *libInstanceTwo = libraryInit.initialize(1);

libInstanceOne->funcOne();
libInstanceTwo->funcOne();
libInstanceOne->funcTwo(libInstanceOne->ctx);
libInstanceTwo->funcTwo(libInstanceTwo->ctx);

libraryInit.deinitialize(libInstanceOne);
libraryInit.deinitialize(libInstanceTwo);

return EXIT_SUCCESS;
}

A nebo použít C++. Můj život má limitovaný čas.
Zrovna C++ je na psaní knihoven velmi nešikovný jazyk. Jedině kdybyste tu knihovnu implementoval celou v hlavičkových souborech a ne jako binárku.

.

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #7 kdy: 30. 04. 2017, 12:11:09 »
A nebo použít C++. Můj život má limitovaný čas.

když už c++, tak to raději něco jiného. Už jen řešit Object slice když chceš používat polymorfismus....

.

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #8 kdy: 30. 04. 2017, 12:16:57 »


To vaše řešení se mi moc nelíbí už jen proto, že používáte malloc, navíc je složitější. To mi přijde lepší použít jednoduše memcpy nad mým řešením:

Kód: [Vybrat]

//MyAnotherFile.h
#include "library.h"
struct library MyNewLibrary = Library;



Neviditelný

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #9 kdy: 30. 04. 2017, 12:43:52 »


To vaše řešení se mi moc nelíbí už jen proto, že používáte malloc, navíc je složitější. To mi přijde lepší použít jednoduše memcpy nad mým řešením:

Kód: [Vybrat]

//MyAnotherFile.h
#include "library.h"
struct library MyNewLibrary = Library;


A co je na mallocu tak špatného? Pokud by ta struktura představující rozhraní knihovny neobsahovala žádné pointery na data, mohl byste ji naalokovat staticky a inicializační funkci knihovny nechat jen vyplnit její obsah. Vytvářet nové instance knihovního rozhraní tím, že tu původní instanci natvrdo zkopírujete je podle mě čuňárna non plus ultra a není mi jasné, k čemu vám to vlastně bude dobré. Kdybyste tento přístup použil ve vašem případě, získáte akorát několik úplně stejných objektů a bude úplně fuk, skzre který ty knihovní funkce zavoláte.

.

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #10 kdy: 30. 04. 2017, 14:08:38 »
Proč nepoužívat malloc? Protože je to pomalejší než stack a musíte řešit přidělování a uvolňování paměti?

Ok, ten můj příklad byl chybný, ale tohle je už zaručeně lepší než to vaše:

Kód: [Vybrat]
//myheader.h

struct library {
    int myInt;
    void (*method)(struct library *,int);
};

extern const struct library Library;

Kód: [Vybrat]
//myheader.c

#include "myheader.h"

static void method(struct library *self, int arg)
{
    self->myInt = arg;
}

const struct library Library = {
        .method = method,
        .myInt = 666
};

Kód: [Vybrat]
//main.c

#include <stdio.h>
#include "myheader.h"


int main() {
    struct library NewLibrary = Library;
    struct library Another = Library;

    Library.method(&NewLibrary, 123);
    NewLibrary.method(&Another, 123456);

    printf("%d \n",NewLibrary.myInt);
    printf("%d ",Another.myInt);
   
    return 0;
}


.

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #11 kdy: 30. 04. 2017, 14:10:26 »
// v main.c mam chybu, misto Library ma byt NewLibrary

Neviditelný

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #12 kdy: 30. 04. 2017, 15:04:15 »
V tom vašem nápadu vidím jeden nedostatek: Pokud byste chtěl použít přímo instanci Library místo nějaké zkopírované, dostanete při volání funkce method() varování při překladu, protože Library je deklarována jako konstantní. Programátora, co by to varování ignoroval zchladí ihned po zavolání funkce method() segfault. Aby to fungovalo správně, je nutné si tu výchozí instanci vždycky zkopírovat. Já bych tohle řešení nepoužil z těchto důvodů:

- Ty zkopírované instance nejsou a nemohou být konstantní a uživatelský kód se v nich může libovolně vrtat.
- Porušují data hiding, interní proměnná myInt je zvenku viditelná a přístupná.
- Nelze tam realizovat polymorfismus. Všimněte si, že moje funkce initialize() může ty function pointery nastavit na jakoukoliv funkci z té knihovny.

.

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #13 kdy: 30. 04. 2017, 16:32:40 »
1 - Ty zkopírované instance nejsou a nemohou být konstantní a uživatelský kód se v nich může libovolně vrtat.
2 - Porušují data hiding, interní proměnná myInt je zvenku viditelná a přístupná.
3 - Nelze tam realizovat polymorfismus. Všimněte si, že moje funkce initialize() může ty function pointery nastavit na jakoukoliv funkci z té knihovny.

1) Zkopírované instance ani nemají být konstantní, konstantní má být jenom ta výchozí instance, aby v ní někdo nemohl přepsat např. ty metody

2) Neporušují data hiding, proměnné a metody které mají být zvenku přístupné jsou v definici te struktury, to co nemá být zvenku viditelné je schované v .c implementaci.

3) No, dejme tomu, mě by to stačilo i bez toho polymorfizmu. Používáte tam malloc a to se mi nelíbí, proč malloc když to může být inicializováno staticky?

Já oproti tomu jako hlavní problém toho mého řešení vidím v tom, že nastane problém v momentě, kdy bych potřeboval ve struktuře mít cokoliv inicializováno dynamicky. V ten moment bych nemohl udělat deep copy. Takže bych se neobešel bez metod

struct library create_library_instance();
void delete_library_instance();

Ale ty bych použil jen v případě, kdyby probíhala nějaká dynamická alokace, jinak by to totiž bylo useless.

.

Re:C - deklarace metod ve stukturach s definici bokem
« Odpověď #14 kdy: 30. 04. 2017, 16:45:33 »
Jo máte vlastně pravdu s tím data hidingem. Nicméně já půdovně nechtěl vůbec roubovat na  Céčko OOP, protože mi to příjde jako totální overkill, tak jsem data hiding neřešil.