Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλημέρα σας,

 

έχω γράψει ένα κώδικα που υπολογίζει γινόμενο πίνακα-διανύσματος

για αραιούς πίνακες σε μορφή αποθήκευσης COO. Τα έκανα όλα κα-

λά αλλά προφανώς δε μπορούσα να σταθώ σε χλωρό κλαρί, οπότε

έβαλα με το νου μου να κάνω τον κώδικα να φαίνεται πιο επίσημος.

Κάθησα έτσι και άρχιζα να εφαρμόζω πραγματάκια που έμαθα από το

βιβλίο Interfaces & Implementations για να του δώσω άλλο αέρα. Όλα

τα έβαλα καλά, αλλά έχω κολλήσει στο garbage collection. Μου φαίνε-

ται περίεργο το πρόβλημα, μπορεί να φταίει και η ώρα.

 

To Interface και το Implementation είναι τα εξής:

coo_sparse.h

 

 

#ifndef COO_SPARSE_H_7EUNGWRE
#define COO_SPARSE_H_7EUNGWRE
#include <stdlib.h> // for size_t

#define T coo_triplet_T
typedef struct T *T;	/* T is a pointer to struct T */

#define COO_LENGTH(A)       (A->nz)
#define COO_GET_VALUE(A, i) (A->val[i])
#define COO_GET_COL_I(A, i) (A->col_ind[i])
#define COO_GET_ROW_I(A, i) (A->row_ind[i])


/** ===========================================================================
 * Creates a matrix in a triplet form according to COO scheme.
 * @param nz Number of non-zero elements
 * @return Pointer to the triplet form
 */
extern T coo_new_triplet(size_t nz);


/** ===========================================================================
 * Initialize the value array of the triplet.
 * @param A Sparse matrix in triplet COO scheme
 * @param val Pointer to the value array
 */
extern void coo_init_value(T A, double *val);


/** ===========================================================================
 * Initialize the column index array of the triplet.
 * @param A Sparse matrix in triplet COO scheme
 * @param val Pointer to the column index array
 */
extern void coo_init_col_ind(T A, size_t *col);


/** ===========================================================================
 * Initialize the row index array of the triplet.
 * @param A Sparse matrix in triplet COO scheme
 * @param val Pointer to the row index array
 */
extern void coo_init_row_ind(T A, size_t *row);


/** ===========================================================================
 * Delete the given sparse matrix which uses the COO scheme.
 * @param A Sparse matrix in triplet COO scheme
 */
extern void coo_delete_triplet(T A);


/** ===========================================================================
 * Multiplies matrix A by vector x and stores the result in vector y.
 * @param A Input matrix
 * @param x Input vactor
 * @param y Result of A*x
 */
extern void coo_sparse_matrix_vector_mul(const T A,
                                         const double *x,
                                         double *y);

#undef T
#endif /* COO_SPARSE_H_7EUNGWRE */
 

 

 

 

coo_sparse.c

 

 

#include "coo_sparse.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>

#define T coo_triplet_T

/**
 * COO triplet data type
 */
struct T {
    double *val;
    size_t *col_ind;
    size_t *row_ind;
    size_t nz;
};


T coo_new_triplet(size_t nz)
{
    T ret = malloc(sizeof(T));

    register size_t bytes = nz * sizeof(size_t);
    ret->val = malloc(nz * sizeof(double));
    ret->col_ind = malloc(bytes);
    ret->row_ind = malloc(bytes);
    ret->nz = nz;

    if (!ret || !ret->val || !ret->col_ind || !ret->row_ind) {
        perror("coo_serial");
        exit(EXIT_FAILURE);
    }

    return ret;
}


void coo_init_value(T A, double *val)
{
    assert(A);
    assert(val);

    memcpy(A->val, val, A->nz * sizeof(double));
}


void coo_init_col_ind(T A, size_t *col)
{
    assert(A);
    assert(col);

    memcpy(A->col_ind, col, A->nz * sizeof(size_t));
}


void coo_init_row_ind(T A, size_t *row)
{
    assert(A);
    assert(row);

    memcpy(A->row_ind, row, A->nz * sizeof(size_t));
}


void coo_delete_triplet(T A)
{
    assert(A);

    free(A->val);     A->val     = NULL;
    free(A->col_ind); A->col_ind = NULL;
    free(A->row_ind); A->row_ind = NULL;
    free(A);          A          = NULL;
}


void coo_sparse_matrix_vector_mul(const T A,
                                  const double *x,
                                  double *y)
{
    assert(A);

    for (size_t i = 0; i < COO_LENGTH(A); i++) {
        y[COO_GET_ROW_I(A, i)] += COO_GET_VALUE(A, i) * x[COO_GET_COL_I(A, i)];
    }
}

#undef T
 

 

 

 

Τα παραπάνω τα χρησιμοποιώ εδώ:

 

 

#include "test_suite.h"
#include "coo_sparse.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void test_suite(void)
{
    /* TEST 1 */
    {
        size_t size = 3;
        size_t nz = 3;
        coo_triplet_T test = coo_new_triplet(nz);

        double val[3]     = {1., 2., 3.};
        size_t col_ind[3] = {0,  2,  2};
        size_t row_ind[3] = {0,  0,  2};
        coo_init_value(test, val);
        coo_init_col_ind(test, col_ind);
        coo_init_row_ind(test, row_ind);

        double x[3]     = {10., 20., 30.};
        double y_sol[3] = {70., 0.,  90.};

        double y_res[3] = {0.};

        coo_sparse_matrix_vector_mul(test, x, y_res);

        if (!memcmp(y_res, y_sol, size * sizeof(double))) {
            puts("[TEST 1] *** SUCCESS ***");
        } else {
            puts("[TEST 1] !!! FAILURE !!!");
        }

        coo_delete_triplet(test);
    }

    /* TEST 2 */
    {
        size_t size = 8;
        size_t nz = 14;
        coo_triplet_T test = coo_new_triplet(nz);

        double val[14]     = {6., 9., 4., 4., 5., 3., 5., 8., 6., 5., 4., 3., 2., 2.};
        size_t col_ind[14] = {0,  2,  5,  5,  1,  2,  3,  4,  4,  5,  5,  6,  6,  7};
        size_t row_ind[14] = {0,  0,  0,  1,  2,  3,  3,  3,  4,  5,  6,  6,  7,  7};
        coo_init_value(test, val);
        coo_init_col_ind(test, col_ind);
        coo_init_row_ind(test, row_ind);

        double x[8]     = { 1., 3.,  6.,  2., 1., 0.,  5.,  3.};
        double y_sol[8] = {60., 0., 15., 36., 6., 0., 15., 16.};

        double y_res[8] = {0.};

        coo_sparse_matrix_vector_mul(test, x, y_res);

        if (!memcmp(y_res, y_sol, size * sizeof(double))) {
            puts("[TEST 2] *** SUCCESS ***");
        } else {
            puts("[TEST 2] !!! FAILURE !!!");
        }

        coo_delete_triplet(test);
    }
}
 

 

 

 

Γενικότερα δεν έχω εισάγει πολυπλοκότητα αλγορίθμων ώστε να έχω τρελά θέματα. Ο κώ-

δικας είναι πολύ απλός, αλλά φαίνεται ότι δεν άντεξα το βάρος του interface έτσι όπως το

έστησα. Επέλεξα να κρατήσω κρυφή τη δομή από τον χρήστη και να του επιτρέπω να τη

διαχειρίζεται μέσω συναρτήσεων.

 

Εκεί που μου εμφανίζει πρόβλημα, σκάει δηλαδή στην εκτέλεση το πρόγραμμα είναι αυτά

που συμβαίνουν στην coo_delete_triplet:

 

 

 ✘ gon1332@localhost ⮀ ~/Dropbox/ΤΜΗΥΤΔ/5ο έτος/Θ - Παράλληλοι και Δικτυακοί Υπολογισμοί/Εργασίες/proj3/src ⮀ ./serial
[TEST 1] *** SUCCESS ***
*** glibc detected *** ./serial: munmap_chunk(): invalid pointer: 0x0000000000d6f030 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x76a16)[0x7fdec5859a16]
./serial[0x400a60]
./serial[0x400d45]
./serial[0x400fa4]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7fdec5801ead]
./serial[0x400659]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:04 10894723                           /home/gon1332/Dropbox/ΤΜΗΥΤΔ/5ο έτος/Θ - Παράλληλοι και Δικτυακοί Υπολογισμοί/Εργασίες/proj3/src/serial
00601000-00602000 rw-p 00001000 08:04 10894723                           /home/gon1332/Dropbox/ΤΜΗΥΤΔ/5ο έτος/Θ - Παράλληλοι και Δικτυακοί Υπολογισμοί/Εργασίες/proj3/src/serial
00d6f000-00d90000 rw-p 00000000 00:00 0                                  [heap]
7fdec55cd000-7fdec55e2000 r-xp 00000000 08:04 394715                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fdec55e2000-7fdec57e2000 ---p 00015000 08:04 394715                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fdec57e2000-7fdec57e3000 rw-p 00015000 08:04 394715                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fdec57e3000-7fdec5965000 r-xp 00000000 08:04 393657                     /lib/x86_64-linux-gnu/libc-2.13.so
7fdec5965000-7fdec5b65000 ---p 00182000 08:04 393657                     /lib/x86_64-linux-gnu/libc-2.13.so
7fdec5b65000-7fdec5b69000 r--p 00182000 08:04 393657                     /lib/x86_64-linux-gnu/libc-2.13.so
7fdec5b69000-7fdec5b6a000 rw-p 00186000 08:04 393657                     /lib/x86_64-linux-gnu/libc-2.13.so
7fdec5b6a000-7fdec5b6f000 rw-p 00000000 00:00 0 
7fdec5b6f000-7fdec5b8f000 r-xp 00000000 08:04 393651                     /lib/x86_64-linux-gnu/ld-2.13.so
7fdec5d66000-7fdec5d69000 rw-p 00000000 00:00 0 
7fdec5d8b000-7fdec5d8e000 rw-p 00000000 00:00 0 
7fdec5d8e000-7fdec5d8f000 r--p 0001f000 08:04 393651                     /lib/x86_64-linux-gnu/ld-2.13.so
7fdec5d8f000-7fdec5d90000 rw-p 00020000 08:04 393651                     /lib/x86_64-linux-gnu/ld-2.13.so
7fdec5d90000-7fdec5d91000 rw-p 00000000 00:00 0 
7fffa146d000-7fffa148e000 rw-p 00000000 00:00 0                          [stack]
7fffa149b000-7fffa149d000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
[1]    12235 abort      ./serial
 

 

 

 

Έτρεξα και τον gdb για να δω τί περνιέται σε κάθε stack frame και όλα μου φαίνονται φυσιολογικά.

Βέβαια αυτό που μου προκαλλεί τις δυσλειτουργίες μπορεί να κρύβεται αλλού όπως συχνά συμβαί-

νει με τη C.

 

gdb output:

 

 

(gdb) bt full
#0  0x00007ffff7a83165 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
        pid = <optimized out>
        selftid = <optimized out>
#1  0x00007ffff7a863e0 in *__GI_abort () at abort.c:92
        act = {__sigaction_handler = {sa_handler = 0x7fffffffd768, sa_sigaction = 0x7fffffffd768}, sa_mask = {__val = {140737488344912, 
              140737488349202, 156, 140737349550107, 3, 140737488344922, 6, 140737349550111, 2, 140737488344910, 2, 140737349541097, 1, 
              140737349550107, 3, 140737488344916}}, sa_flags = 12, sa_restorer = 0x7ffff7ba001f}
        sigs = {__val = {32, 0 <repeats 15 times>}}
#2  0x00007ffff7abe1cb in __libc_message (do_abort=<optimized out>, fmt=<optimized out>) at ../sysdeps/unix/sysv/linux/libc_fatal.c:189
        ap = {{gp_offset = 40, fp_offset = 48, overflow_arg_area = 0x7fffffffe0d0, reg_save_area = 0x7fffffffdfe0}}
        ap_copy = {{gp_offset = 16, fp_offset = 48, overflow_arg_area = 0x7fffffffe0d0, reg_save_area = 0x7fffffffdfe0}}
        fd = 3
        on_2 = <optimized out>
        list = <optimized out>
        nlist = 0
        cp = <optimized out>
        written = false
#3  0x00007ffff7ac7a16 in malloc_printerr (action=3, str=0x7ffff7ba2098 "munmap_chunk(): invalid pointer", ptr=<optimized out>) at malloc.c:6312
        buf = "0000000000602030"
        cp = 0x7ffff7b97d40 <_itoa_lower_digits> "0123456789abcdefghijklmnopqrstuvwxyz"
#4  0x0000000000400a60 in coo_delete_triplet (A=0x602010) at coo_sparse.c:69
No locals.
#5  0x0000000000400d45 in test_suite () at test_suite.c:35
        nz = 3
        test = 0x602010
        val = {1, 2, 3}
        size = 3
        col_ind = {0, 2, 2}
        row_ind = {0, 0, 2}
        x = {10, 20, 30}
        y_sol = {70, 0, 90}
        y_res = {70, 0, 90}
#6  0x0000000000400fa4 in main () at coo_serial.c:8
No locals. 

 

 

 

Όλα φαίνονται ok, και τα tests που έφτιαξα περνάνε αν βάλω σε σχόλια το garbage collection.

Τι μπορεί να φταίει;

 

ΣΗΜΕΙΩΣΗ: Ο κώδικας δουλεύει ως έχει και έχω έκδοση που δουλεύουν όλα ρολόι,

απλά θέλω να δοκιμάσω στην πράξη κάποια πράγματα για να μάθω από αυτά.

 

Έχω σε attachment όλο τον κώδικα μαζί με makefile. Ο κώδικας έχει δοκιμαστεί μόνο σε linux,

χωρίς όμως να περιέχει τίποτα το unix-οειδές.

 

Επίσης δεν έχω πρόβλημα να χρησιμοποιηθεί ότι έχω γράψει από τρίτους. Έτσι κι αλλιώς το

τελικό αποτέλεσμα θα ανέβει public σε κάποιο repository.

Δημοσ.

Κλασική περίπτωση δαγκώματος από typdef που κρύβει pointer μέσα του (και δυστυχώς ευρέως διαδεδομένη πρακτική :( ).

 

Ένα από τα ακόλουθα είναι πολύ καλύτερο, αν και η προσωπική μου παρότρυνση είναι μονάχα το 1ο που είναι τελείως ξεκάθαρο (γιατί το 2ο βασίζεται στην ονομασία του identifier που θα δώσεις για τον τύπο... στην προκειμένη περίπτωση περιέχει δηλαδή το "Ptr").

typedef struct T { ... } T;
T *p;

ή

typedef struct T { ... } *TPtr;
TPtr p;
EDIT:

 

Επίσης αν συνηθίσεις να...

p = malloc( sizeof(*p) );
θα δουλεύει σωστά είτε με...

T *p = malloc( sizeof(*p) );
είτε με...

TPtr p = malloc( sizeof(*p) );
  • Like 1
Δημοσ.

Ευχαριστώ! Μπορεί και να μην το έβλεπα. Ήταν η πρώτη φορά

που έκανα μία τέτοια υπέρβαση για να πάνε όλα καλά. Συνέχεια

χρησιμοποιώ τις πρώτες περιπτώσεις που πρότεινε ο migf1.

Απ' ότι φαίνεται θα συνεχίσω κατά τα παλιά και τα πιο συνηθισ-

μένα.

  • Like 1
Δημοσ.

Βασικά, αν έχεις δεδομένο το να μην κρύβεις δείκτες μέσα σε typedef, τότε "ελευθερώνεσαι" και στην χρήση της malloc(), μιας και μπορείς να κάνεις είτε T *p = malloc( sizeof(*p) ); είτε T *p = malloc( sizeof(T) );

Δημοσ.

Δες εδω

#ifndef COO_SPARSE_H_7EUNGWRE
#define COO_SPARSE_H_7EUNGWRE
#include <stdlib.h> // for size_t


typedef struct _coo_matrix_tag *coo_matrix;

coo_matrix	coo_matrix_new();
void		coo_matrix_delete(coo_matrix matrix);
double		coo_matrix_get(const coo_matrix matrix, int r,int c);
coo_matrix	coo_matrix_set(coo_matrix matrix, int r, int c, double val);



#endif /* COO_SPARSE_H_7EUNGWRE */

Ολες οι συναρτησεις που εχουν σχεση με το coo_matrix, αρχιζουν απο το coo_matrix, γιατι; 

Για αυτο

quSnSIO.png

 

οταν θες να κανεις encapsulate ενα struct τοτε φτιαχνεις εναν incomplete struct

typedef struct _coo_matrix_tag *coo_matrix;

example

#include "coo.h"


int main()
{
	
	coo_matrix m = coo_matrix_new();

	coo_matrix_set(m,0,0,1.);
	coo_matrix_set(m,1,1,2.);
	coo_matrix_set(m,2,2,3.);
	coo_matrix_set(m,3,3,4.);
	coo_matrix_set(m,4,4,5.);
	coo_matrix_set(m,5,5,6.);
	

	//print
	for(int i = 0; i < 6; i++)
	{
		for(int j = 0 ; j < 6 ; j++)
		{
			std::cout<<coo_matrix_get(m,i,j)<< "\t";
		}
		std::cout<<std::endl;
	}

	coo_matrix_delete(m);


	return 0;
}

out

1       0       0       0       0       0
0       2       0       0       0       0
0       0       3       0       0       0
0       0       0       4       0       0
0       0       0       0       5       0
0       0       0       0       0       6

imp

 

 

#include "coo.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>

typedef struct coo_node_tag
{
	double val;
	int r;
	int c;
	coo_node_tag *next;
}coo_node;

struct _coo_matrix_tag
{
	/*
	edw mporoyn na mpoyn kai alla pramata
	px original size
	allocators etc
	*/
	coo_node *head;
};


coo_matrix coo_matrix_new()
{
	coo_matrix matrix;
	matrix				= (coo_matrix) malloc(sizeof (struct _coo_matrix_tag)  );
	matrix->head		= NULL;
	return matrix;
}
void coo_matrix_delete(coo_matrix matrix)
{
	coo_node *node = matrix->head;
	while( node != NULL)
	{
		coo_node *tmp = node->next;
		free(node);
		node = tmp;
	}
	free(matrix);
	
}
coo_matrix coo_matrix_set(coo_matrix matrix, int r, int c, double val)
{
	coo_node *node = matrix->head;
	if(!node)
	{
		matrix->head			= (coo_node*)malloc(sizeof(coo_node));
		matrix->head->r			= r;
		matrix->head->c			= c;
		matrix->head->val		= val;
		matrix->head->next		= NULL;
		return matrix;
	}
	
	while(1)
	{
		if(node->r == r && node->c == c)
		{
			node->val = val;
			return matrix;
		}
		if(node->next == NULL)
		{
			node->next			= (coo_node*)malloc(sizeof(coo_node));
			node->next->r		= r;
			node->next->c		= c;
			node->next->val		= val;
			node->next->next	= NULL;
			return matrix;
		}
		node = node->next;
	}
}
double coo_matrix_get(const coo_matrix matrix, int r,int c)
{
	coo_node *node = matrix->head;
	for(; node != NULL; node = node->next)
		if(node->r == r && node->c == c)
			return node->val;
	return 0.0;
} 

 

 

Δημοσ.

Βασικά, αν έχεις δεδομένο το να μην κρύβεις δείκτες μέσα σε typedef, τότε "ελευθερώνεσαι" και στην χρήση της malloc(), μιας και μπορείς να κάνεις είτε T *p = malloc( sizeof(*p) ); είτε T *p = malloc( sizeof(T) );

Αυτό που έκανα μπορούσε να διορθωθεί με μία γραμμή T p = malloc(sizeof(*p));

αλλά καλύτερα να μη μου γίνει συνήθεια.

Δες εδω

 

 

#ifndef COO_SPARSE_H_7EUNGWRE
#define COO_SPARSE_H_7EUNGWRE
#include <stdlib.h> // for size_t


typedef struct _coo_matrix_tag *coo_matrix;

coo_matrix	coo_matrix_new();
void		coo_matrix_delete(coo_matrix matrix);
double		coo_matrix_get(const coo_matrix matrix, int r,int c);
coo_matrix	coo_matrix_set(coo_matrix matrix, int r, int c, double val);



#endif /* COO_SPARSE_H_7EUNGWRE */

Ολες οι συναρτησεις που εχουν σχεση με το coo_matrix, αρχιζουν απο το coo_matrix, γιατι; 

Για αυτο

quSnSIO.png

 

οταν θες να κανεις encapsulate ενα struct τοτε φτιαχνεις εναν incomplete struct

typedef struct _coo_matrix_tag *coo_matrix;

example

#include "coo.h"


int main()
{
	
	coo_matrix m = coo_matrix_new();

	coo_matrix_set(m,0,0,1.);
	coo_matrix_set(m,1,1,2.);
	coo_matrix_set(m,2,2,3.);
	coo_matrix_set(m,3,3,4.);
	coo_matrix_set(m,4,4,5.);
	coo_matrix_set(m,5,5,6.);
	

	//print
	for(int i = 0; i < 6; i++)
	{
		for(int j = 0 ; j < 6 ; j++)
		{
			std::cout<<coo_matrix_get(m,i,j)<< "\t";
		}
		std::cout<<std::endl;
	}

	coo_matrix_delete(m);


	return 0;
}

out

1       0       0       0       0       0
0       2       0       0       0       0
0       0       3       0       0       0
0       0       0       4       0       0
0       0       0       0       5       0
0       0       0       0       0       6

imp

 

 

#include "coo.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>

typedef struct coo_node_tag
{
	double val;
	int r;
	int c;
	coo_node_tag *next;
}coo_node;

struct _coo_matrix_tag
{
	/*
	edw mporoyn na mpoyn kai alla pramata
	px original size
	allocators etc
	*/
	coo_node *head;
};


coo_matrix coo_matrix_new()
{
	coo_matrix matrix;
	matrix				= (coo_matrix) malloc(sizeof (struct _coo_matrix_tag)  );
	matrix->head		= NULL;
	return matrix;
}
void coo_matrix_delete(coo_matrix matrix)
{
	coo_node *node = matrix->head;
	while( node != NULL)
	{
		coo_node *tmp = node->next;
		free(node);
		node = tmp;
	}
	free(matrix);
	
}
coo_matrix coo_matrix_set(coo_matrix matrix, int r, int c, double val)
{
	coo_node *node = matrix->head;
	if(!node)
	{
		matrix->head			= (coo_node*)malloc(sizeof(coo_node));
		matrix->head->r			= r;
		matrix->head->c			= c;
		matrix->head->val		= val;
		matrix->head->next		= NULL;
		return matrix;
	}
	
	while(1)
	{
		if(node->r == r && node->c == c)
		{
			node->val = val;
			return matrix;
		}
		if(node->next == NULL)
		{
			node->next			= (coo_node*)malloc(sizeof(coo_node));
			node->next->r		= r;
			node->next->c		= c;
			node->next->val		= val;
			node->next->next	= NULL;
			return matrix;
		}
		node = node->next;
	}
}
double coo_matrix_get(const coo_matrix matrix, int r,int c)
{
	coo_node *node = matrix->head;
	for(; node != NULL; node = node->next)
		if(node->r == r && node->c == c)
			return node->val;
	return 0.0;
} 

 

 

 

 

 

Θέτοντας τα ονόματα των συναρτήσεων όπως τα έθεσες εσύ, υποδεικνύουν ότι

εφαρμόζονται πάνω στη βασική δομή την οποία υλοποιούμε και υποστηρίζουμε.

Επίσης ο χρήστης γνωρίζοντας το πρόθεμα, το οποίο είναι κοινό για όλες, αρκεί

να θυμάται μόνο τις πράξεις που μπορεί να κάνει πάνω στη δομή μας. Στην ου-

σία πετυχαίνουμε ένα feeling OO. Το παράδειγμα που έδωσες μου άρεσε. Δεν

περίμενα υλοποίηση με λίστες. Με εξέπληξες :D. Στην ουσία encapsulation ήθε-

λα να επιτύχω με λίγη αποτυχία. Θα προσπαθήσω να  το βελτιώσω λιγάκι με το

δικό μου implementation (καθώς πρέπει να βελτιστοποιηθεί) σύμφωνα με τις ο-

δηγίες σας στο interface.

Δημοσ.

Το ξέρω πως λύνεται μόνο με αυτή τη γραμμή, για αυτό σου την υπέδειξα κιόλας στο 1ο ποστ. Στο 2ο ποστ σου παρουσιάσα μια εναλλακτική "ανάποδη" προσέγγιση. Δηλαδή, αντί να έχεις fixed malloc() και alternative typedefs, να έχεις fixed typedef και alternative malloc()'s.

 

Παρεμπιπτόντως, το encapsulation δεν απαιτεί υποχρεωτικά κρύψιμο δεικτών μέσα σε typdefs. Εδώ χρησιμοποιώ κατά κύριο λόγο encapsulations που ΔΕΝ κρύβουν τον βασικό δείκτη από τον χρήστη, με εξαίρεση τους iterators όπου αιτιολογώ (στα "Remarks" του 2ου link) για ποιον λόγο το κάνω (γιατί δλδ κρύβω δείκτη μέσα στα iterator types).

Δημοσ.

Θέτοντας τα ονόματα των συναρτήσεων όπως τα έθεσες εσύ, υποδεικνύουν ότι

εφαρμόζονται πάνω στη βασική δομή την οποία υλοποιούμε και υποστηρίζουμε.

Επίσης ο χρήστης γνωρίζοντας το πρόθεμα, το οποίο είναι κοινό για όλες, αρκεί

να θυμάται μόνο τις πράξεις που μπορεί να κάνει πάνω στη δομή μας. Στην ου-

σία πετυχαίνουμε ένα feeling OO.

Δεν πετυχαινουμε ενα OO feeling... Πετυχαινουμε ολα τα αλλα που ειπες. Ενα ευκολο στη χρηση API.
Δημοσ.

Δεν πετυχαινουμε ενα OO feeling... Πετυχαινουμε ολα τα αλλα που ειπες. Ενα ευκολο στη χρηση API.

Συμφωνώ με τον gon εγώ. Άσχετα με το κρύψιμο ή όχι του δείκτη σε typedef, αυτή η πρακτική αποτελεί βασικό μηχανισμό για OOP προσέγγιση με C. Τόσο το πρώτο συστατικό στο όνομα των συναρτήσεων όσο και ο δείκτης ως πρώτο τους όρισμα υποδηλώνουν το object στο οποίο αναφέρονται (δηλαδή με άλλα λόγια, αποτελούν τα methods του εν λόγω object). Προφανώς όμως υπάρχουν και πιο σύνθετες υλοποιήσεις.

Δημοσ.

Συμφωνώ με τον gon εγώ. Άσχετα με το κρύψιμο ή όχι του δείκτη σε typedef, αυτή η πρακτική αποτελεί βασικό μηχανισμό για OOP προσέγγιση με C. Τόσο το πρώτο συστατικό στο όνομα των συναρτήσεων όσο και ο δείκτης ως πρώτο τους όρισμα υποδηλώνουν το object στο οποίο αναφέρονται (δηλαδή με άλλα λόγια, αποτελούν τα methods του εν λόγω object). Προφανώς όμως υπάρχουν και πιο σύνθετες υλοποιήσεις.

Με βάση αυτό που ανέφερες έβγαλα αυτό το συμπέρασμα. Πιστεύω ότι οι συμβάσεις στην ονομασία είναι

ο πιο απλός τρόπος να προσποιηθείς OOP σε C. Πριν πας δηλαδή σε function pointers και κληρονομικό-

τητες.

 

Έχω και κάποια ερωτήματα πάνω σε εργαλεία documentation και unit-testing, τα οποία θα ήθελα να δοκιμά-

σω πάνω σε αυτό το απλό project. Θα ανοίξω όμως σύντομα άλλο νήμα γι' αυτό το λόγο.

Δημοσ.

Με βάση αυτό που ανέφερες έβγαλα αυτό το συμπέρασμα. Πιστεύω ότι οι συμβάσεις στην ονομασία είναι

ο πιο απλός τρόπος να προσποιηθείς OOP σε C. Πριν πας δηλαδή σε function pointers και κληρονομικό-

τητες.

Ακόμα και τότε, οι συμβάσεις στις ονομασίες παραμένουν πάνω-κάτω όπως περιγράφηκε, διότι η C δεν επιτρέπει name-mangling.

 

EDIT:

 

Απλώς αν βάλεις function-pointers μέσα στο struct που περιγράφει το object ("μεθοδους" μέσα την "κλάση" δηλαδή), τότε αντί να γράφεις π.χ. obj_do_that( obj ); θα γράφεις obj->do_that( obj );

 

Το θέμα είναι πως και στις 2 περιπτώσεις περνάς το obj ως 1η παράμετρο της μεθόδου. Μπορείς να το αποφύγεις (άσχετα με το αν θα υλοποιήσεις ή όχι τις μεθόδους με function-pointers), αλλά συνήθως ο έξτρα κώδικας που χρειάζεται για κάτι τέτοιο δεν αξίζει τον κόπο (οπότε αντί για function pointers μέσα στο struct, φτιάχνεις απλώς ένα έξτρα αρχείο class_τάδε.c με τους ορισμούς των "μεθόδων" και τους περνάς πάντα ως 1η παράμετρο έναν δείκτη στο ήδη instantiated object).

Δημοσ.

Με βάση αυτό που ανέφερες έβγαλα αυτό το συμπέρασμα. Πιστεύω ότι οι συμβάσεις στην ονομασία είναι

ο πιο απλός τρόπος να προσποιηθείς OOP σε C. Πριν πας δηλαδή σε function pointers και κληρονομικό-

τητες.

 

Δεν πάνε μαζί απαραίτητα αυτά. Μπορείς να έχεις OO χωρίς virtual functions και άρα χωρίς function pointers για vtable.

Δημοσ.

Τρέξε τον κώδικα σου μέσω valgrind ώστε να δεις το προφιλ του πιο καθαρά (memory leaks, invalid writes/reads, etc.). Από τα (δυστυχώς) λιγοστά αξιόλογα εργαλεία για να δουλέψεις πάνω σε C κώδικα.

 

http://valgrind.org/


Btw, όποιος έχει τον χρόνο και την όρεξη: Object oriented programming with ANSI-C 

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...