Vad ska jag använda för programmeringsmetodik vid många funktioner - C

Permalänk
Skrivet av pelleplu:

Från din kod:

/* * Fields that can be access with getters and setters */ char* host; char* user; char* pass; char* dbname;

Dessa kommer att vara tillgängliga utanför din .c-fil om du inte deklarerar dom med "static" ordet före, dvs:

static char* host; static char* user; static char* pass; static char* dbname;

Samma sak om du har funktioner i din .c-fil som du inte vill ska vara åtkomliga utanför den aktuella filen, då måste dom också deklareras/definieras med static först. Eftersom du verkar vilja isolera åtkomst till själva variablerna med getters/setters så antar jag att du också vill förhindra direkt åtkomst till dom "utifrån".

Tack! Mycket bra förklarat! Ja. Jag vill hindra mig själv från att fuska i koden

Nu blev det en fin struktur.

Permalänk
Skrivet av anon214822:

C++ är inte bättre än C, bara större. I praktiken använder man oftast en definierad delmängd av C++, s.k. C++--.

Jag älskar C och avskyr C++. Jag gillar vad Linus Torvalds säger om C++, att det bästa med att inte använda C++ är att man slipper att ha att göra med de som gillar C++. Linux är skrivet i C.

Större == Bättre.

Själv föredrar jag C++ före C alla dagar. Men valet av C och C++ avgör vad man sitter i för system och vilket behov man har.

Linus Torvalds har fel. För det första så klankade han ned på C++ innan C++ fick sin standard 1998. Hade C++ kommit på 70-talet så hade Linux varit skrivit i C++.

Men orsaken varför jag väljer att koda i C har med mitt behov av objektorientering finns inte på hårdvarunivå. När jag kör skrivbordsapplikationer osv så är det Java som gäller för mig. Jag finner alltså inget behov av C++.

Permalänk
Hedersmedlem

Jag förstår inte riktigt din tanke med att ha en massa getters och setters. Allt det gör är att skapa mer boilerplatekod. C är som sagt inte Java.

Om du ogillar en massa statiska variabler som förorenar ditt namespace så blir det ju inte bättre av att du istället förorenar ditt namespace med en massa getters/setters.

Mitt förslag är att du skapar en struct som håller ditt state. T.ex. något i stil med:

struct mysqldb { char* host; char* user; char* pass; char* dbname; uint16_t port; /* en TCP port är en 16 bitars int... */ char* socket; /* ??? ser ut som fel typ */ unsigned int flag; }

Sedan skickar du med detta till saker som mysqldb_connect() och mysql_disconnect(). Skapa datastrukturen finns det olika sätt att göra på. T.ex.:

/* denna funktion lägger du rimligen i typ mysqldb.c */ struct mysqldb *mysqldb_new(void) { struct mysqldb *db = calloc(1, sizeof (*db)); /* calloc, typ som malloc, men fyller med nollor */ /* calloc kan returnera NULL om det är slut på minne, så vi får koll på detta */ if (db != NULL) { /* följ bara pekaren db om den pekar på något vettigt, annars får du ett segfault! */ db->port = 3306; /* vi förställer porten till 3306, men låter anroparen ändra den vid behov! */ } /* returnerar antingen en pekare till en initierad "struct mysqldb" eller NULL vid minnesbrist */ return db; } int mysqldb_connect(struct mysqldb *db) { /* magi */ return 0; } /* och här är vi i typ main.c */ int main(int argc, char *argv[]) { struct mysqldb *db = mysqldb_new(); if (db == NULL) { /* error, slut på minne! */ exit(1); } int ret; db->host = "mysql.1177.se"; db->user = "internetsladd"; db->pass = "kommandorörelse"; db->namn = "samtalsinspelningar"; ret = mysqldb_connect(db); if (ret != 0) { /* error */ exit(2); } /* ... */ return 0; }

Du kan så klart också lägga upp en massa argument till mysqldb_new() om du vill, men själv känner jag att det blir mer läsbart på det här sättet än att ha en lång argumentlista där man måste slå upp vad argumenten betyder.

Permalänk
Skrivet av pv2b:

Jag förstår inte riktigt din tanke med att ha en massa getters och setters. Allt det gör är att skapa mer boilerplatekod. C är som sagt inte Java.

Om du ogillar en massa statiska variabler som förorenar ditt namespace så blir det ju inte bättre av att du istället förorenar ditt namespace med en massa getters/setters.

Mitt förslag är att du skapar en struct som håller ditt state. T.ex. något i stil med:

struct mysqldb { char* host; char* user; char* pass; char* dbname; uint16_t port; /* en TCP port är en 16 bitars int... */ char* socket; /* ??? ser ut som fel typ */ unsigned int flag; }

Sedan skickar du med detta till saker som mysqldb_connect() och mysql_disconnect(). Skapa datastrukturen finns det olika sätt att göra på. T.ex.:

/* denna funktion lägger du rimligen i typ mysqldb.c */ struct mysqldb *mysqldb_new(void) { struct mysqldb *db = calloc(1, sizeof (*db)); /* calloc, typ som malloc, men fyller med nollor */ if (db != NULL) { db->port = 3306; /* vi förställer porten till 3306, men låter anroparen ändra den vid behov! */ } return db; } int mysqldb_connect(struct mysqldb *db) { /* magi */ return 0; } /* och här är vi i typ main.c */ int main(int argc, char *argv[]) { struct mysqldb *db = mysqldb_new(); if (db == NULL) { /* error */ exit(1); } int ret; db->host = "mysql.1177.se"; db->user = "internetsladd"; db->pass = "kommandorörelse"; db->namn = "samtalsinspelningar"; ret = mysqldb_connect(db); if (ret != 0) { /* error */ exit(2); } /* ... */ return 0; }

Du kan så klart också lägga upp en massa argument till mysqldb_new() om du vill, men själv känner jag att det blir mer läsbart på det här sättet än att ha en lång argumentlista där man måste slå upp vad argumenten betyder.

Ja. Om jag använder struct så kan jag ha mer lik objektorientering, fast själva objektet ligger i strukturen.

Jag använder inte malloc och calloc.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Ja. Om jag använder struct så kan jag ha mer lik objektorientering, fast själva objektet ligger i strukturen.

Jag använder inte malloc och calloc.

Att inte använda malloc och calloc är ju helt ok, särskilt på kanske en inbäddad plattform. Om du VET att du i ditt program bara någonsin kommer ha en enda databasanslutning kan du ju typ göra så här:

struct mysqldb { char* host; char* user; char* pass; char* dbname; uint16_t port = 3306; /* en TCP port är en 16 bitars int... tror det är OK att initiera den så här */ } mysqldb_connection_parameters; /* nu bryter vi ut socket och flag, de behöver inte exponeras till någon annan modul ändå. */ static char* socket; /* ??? ser ut som fel typ */ static unsigned int flag;

Sedan kan du göra typ så här från anropande modul:

int main(int argc, char *argv[]) { int ret; mysqldb_connection_parameters.host = "mysql.1177.se"; mysqldb_connection_parameters.user = "internetsladd"; mysqldb_connection_parameters.pass = "kommandorörelse"; mysqldb_connection_parameters.namn = "samtalsinspelningar"; ret = mysqldb_connect(); if (ret != 0) { /* error */ exit(2); } /* ... */ return 0; }

Permalänk
Skrivet av pv2b:

Att inte använda malloc och calloc är ju helt ok, särskilt på kanske en inbäddad plattform. Om du VET att du i ditt program bara någonsin kommer ha en enda databasanslutning kan du ju typ göra så här:

struct mysqldb { char* host; char* user; char* pass; char* dbname; uint16_t port = 3306; /* en TCP port är en 16 bitars int... tror det är OK att initiera den så här */ } mysqldb_connection_parameters; /* nu bryter vi ut socket och flag, de behöver inte exponeras till någon annan modul ändå. */ static char* socket; /* ??? ser ut som fel typ */ static unsigned int flag;

Sedan kan du göra typ så här från anropande modul:

int main(int argc, char *argv[]) { int ret; mysqldb_connection_parameters.host = "mysql.1177.se"; mysqldb_connection_parameters.user = "internetsladd"; mysqldb_connection_parameters.pass = "kommandorörelse"; mysqldb_connection_parameters.namn = "samtalsinspelningar"; ret = mysqldb_connect(); if (ret != 0) { /* error */ exit(2); } /* ... */ return 0; }

Ska jag då deklarera alla strukturer då i headerfilerna? Typ som när jag behöver ett nytt objekt så skapar jag bara ny struktur med parametrar och sedan så skickar jag adressen från strukturen till själva funktionerna? Då skulle jag säkert slippa alla getters och setters funktioner.

Då anropar jag bara funktionerna som de är, med strukturen som t.ex. första argumentet t.ex. connect(minStruktur)

?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Ska jag då deklarera alla strukturer då i headerfilerna? Typ som när jag behöver ett nytt objekt så skapar jag bara ny struktur med parametrar och sedan så skickar jag adressen från strukturen till själva funktionerna? Då skulle jag säkert slippa alla getters och setters funktioner.

Då anropar jag bara funktionerna som de är, med strukturen som t.ex. första argumentet t.ex. connect(minStruktur)

?

Det skulle absolut kunna vara ett alternativ! Då hamnar du i typ:

mysql.h

struct mysqldb { char* host; char* user; char* pass; char* dbname; uint16_t port; /* en TCP port är en 16 bitars int... */ static char* socket; /* ??? ser ut som fel typ */ static unsigned int flag; }; int mysqldb_init(struct mysqldb *); int mysqldb_connect(struct mysqldb *);

mysql.c

#include "mysql.h" int mysqldb_init(struct mysqldb *db) { memset(db, 0, sizeof(*db)); db->port = 3306; return 0; } int mysqldb_connect(struct mysqldb *db) { /* ... */ return 0; /* allt ok! */ }

main.c

#include "mysql.h" int main(int argc, char *argv[]) { int ret; struct mysqldb db; /* den här kanske kan vara en global variabl i main.c istället */ mysqldb_init(&db); db.host = "mysql.1177.se"; db.user = "internetsladd"; db.pass = "kommandorörelse"; db.namn = "samtalsinspelningar"; ret = mysqldb_connect(&db); if (ret != 0) { /* error */ exit(2); } /* ... */ return 0; }

Finns mer fancy sätt att initiera strukturer på, men det här är det enklaste sättet.

Permalänk
Skrivet av pv2b:

Det skulle absolut kunna vara ett alternativ! Då hamnar du i typ:

mysql.h

struct mysqldb { char* host; char* user; char* pass; char* dbname; uint16_t port; /* en TCP port är en 16 bitars int... */ static char* socket; /* ??? ser ut som fel typ */ static unsigned int flag; }; int mysqldb_init(struct mysqldb *); int mysqldb_connect(struct mysqldb *);

mysql.c

#include "mysql.h" int mysqldb_init(struct mysqldb *db) { memset(db, 0, sizeof(*db)); db->port = 3306; return 0; } int mysqldb_connect(struct mysqldb *db) { /* ... */ return 0; /* allt ok! */ }

main.c

#include "mysql.h" int main(int argc, char *argv[]) { int ret; struct mysqldb db; /* den här kanske kan vara en global variabl i main.c istället */ mysqldb_init(&db); db.host = "mysql.1177.se"; db.user = "internetsladd"; db.pass = "kommandorörelse"; db.namn = "samtalsinspelningar"; ret = mysqldb_connect(&db); if (ret != 0) { /* error */ exit(2); } /* ... */ return 0; }

Finns mer fancy sätt att initiera strukturer på, men det här är det enklaste sättet.

Vad tror du om denna då? Denna fungerar riktigt bra Fin struktur och lite kod. Såg att du fick error på din .h fil.

* * Constants in this .c files that cannot be accessed from outside */ static const unsigned int port = 3306; static const char* socket = NULL; static const unsigned int flag = 0; /* * Connect to our mysql server */ int connectMySQL(struct DB* mysql) { mysql->conn = mysql_init(NULL); if (!(mysql_real_connect(mysql->conn, mysql->host, mysql->user, mysql->pass, mysql->dbname, port, socket, flag))) { fprintf(stderr, "Error: %s [%d]\n", mysql_error(mysql->conn), mysql_errno(mysql->conn)); return -1; }else{ printf("Connected to database %s via the user %s \n", mysql->dbname, mysql->user); } return 0; } /* * Disconnect from mysql server */ int disconnectMySQL(struct DB* mysql) { //mysql_free_result(res); mysql_close(mysql->conn); return 0; } /* * Write our query */ int writeQuery(struct DB* mysql, char* query) { if (mysql_query(mysql->conn, query)) { fprintf(stderr, "%s: query = %s\n", mysql_error(mysql->conn), query); return -1; }else{ printf("Writing to the database\n"); } return 0; }

Och headern

/* * For MySQL */ struct DB{ char* host; char* user; char* pass; char* dbname; MYSQL* conn; }; int connectMySQL(struct DB* mysql); int disconnectMySQL(struct DB* mysql); int writeQuery(struct DB* mysql, char* query);

Permalänk
Hedersmedlem

Ja! Det ser rätt så vettigt ut ändå, om vi ser på själva kodstrukturen, d.v.s. att bryta upp det hela i delar.

Om vi ser till själva strukturen alltså. Men om vi ser till *vad* koden gör som du visat så ifrågasätter jag om någon av koden behövs alls. Jag tror att du försöker skriva din kod för generellt. Du behöver egentligen ingen modul för att interagera med en MySQL-databas i allmänhet (ett sånt libb finns redan och du behöver ju inte bara lägga ett eget lager runt i onödan). Jag tror du gör gott i att försöka skapa en bra abstraktion. Kanske snarare något som hjälper dig interagera med just din applikations databas, snarare än databaser i allmänhet.

Men det kommer nog

Permalänk
Skrivet av pv2b:

Ja! Det ser rätt så vettigt ut ändå, om vi ser på själva kodstrukturen, d.v.s. att bryta upp det hela i delar.

Om vi ser till själva strukturen alltså. Men om vi ser till *vad* koden gör som du visat så ifrågasätter jag om någon av koden behövs alls. Jag tror att du försöker skriva din kod för generellt. Du behöver egentligen ingen modul för att interagera med en MySQL-databas i allmänhet (ett sånt libb finns redan och du behöver ju inte bara lägga ett eget lager runt i onödan). Jag tror du gör gott i att försöka skapa en bra abstraktion. Kanske snarare något som hjälper dig interagera med just din applikations databas, snarare än databaser i allmänhet.

Men det kommer nog

Jag förstår vad du menar. Jag tycker att de flesta C-bibliotek är rätt så krångligt skrivna. Man ska alltid hålla på deklarera typ massvis med andra saker innan man kan göra det man vill göra. Därför skriver jag in funktioner i en funktion så man behöver bara anropa en enda funktion.

Automatisera med andra ord.