Star_Light έγραψε:
...
Παντως ειναι πολυ πιο βελτιστο πιστευω να περνάς σαν παράμετρο μεσα σε μια συνάρτηση την επιλογη του χρηστη απο το να οριζεις μια switch και αναλογα την ετικέτα της να καλεις την καθε συναρτηση ξεχωριστα που υλοποιει ας πουμε καθε πραξη ξεχωριστα... θυμαμαι σε κατι υλοποιησεις παλαιοτερα στην σχολη αυτο ειχα κανει! Ο χείριστος!!!!!
Έτσι είναι πιο γρήγορο, μπορεί όμως να υπάρχουν περιπτώσεις που να εξυπηρετεί καλύτερα με ξεχωριστές συναρτήσεις. Δεν έχει δηλαδή λάθος και σωστό.
Σου έφτιαξα στα γρήγορα μια μικρή βιβλιοθήκη libop, που κάνει ότι πόσταρες κι εσύ αλλά με ξεχωριστές συναρτήσεις για κάθε ξεχωριστό τύπο δεδομένων και με καλύτερο error checking.
Σε γενικές γραμμές, όταν γράφεις βιβλιοθήκες πρέπει να είσαι πολύ πιο προσεκτικός και σφαιρικός στις υλοποιήσεις σου, γιατί οι βιβλιοθήκες μπορούν να χρησιμοποιηθούν σε πάρα πολλά πρότζεκτ. Επίσης, δεν είναι καλή ιδέα να βάζεις τις συναρτήσεις της βιβλιοθήκης να τυπώνουν μηνύματα. Αντίθετα, είναι καλή ιδέα να τις βάζεις να επιστρέφουν τιμές σφάλματος όταν κάτι πάει στραβά, τις οποίες τιμές επιστροφής μπορεί να τις τσεκάρει όποιος χρησιμοποιεί τη βιβλιοθήκη και να τυπώσει εκείνος ότι μήνυμα επιθυμεί.
Σε αυτό που σου έφτιαξα, η συνάρτηση που κάνει πράξεις σε int επιστρέφει INT_MIN αν κάτι πάει στραβά, εκείνη που κάνεις πράξεις σε long int επιστρέφει LONG_MIN αν κάτι πάει στραβά, εκείνη για float επιστρέφει FLT_MIN κι εκείνη για double επιστρέφει DBL_MIN.
Αυτές τις τιμές πρέπει να τις ελέγχει το δοκιμαστικό πρόγραμμα που έφτιαξα να χρησιμοποιεί την βιβλιοθήκη, για να δει αν υπήρξε κάποιο πρόβλημα όταν κάλεσε κάποια από τις παραπάνω συναρτήσεις.
Για να το κάνω λίγο πιο εύκολο να το θυμάται ο χρήστης της βιβλιοθήκης, τους ελέγχους αυτούς τους έφτιαξα σε 4 αντίστοιχα macros:
- Κώδικας: Επιλογή όλων
OP_INT_ISERROR(n)
OP_LONG_ISERROR(l)
OP_FLT_ISERROR(f)
OP_DBL_ISERROR(d)
μπορεί να χρησιμοποιεί απευθείας αυτά για να δει αν απέτυχε ή όχι η κλήση της αντίστοιχης συνάρτησης. Βασικά αυτά χρησιμοποιώ κι εγώ στο δοκιμαστικό προγραμματάκι test.c
- Κώδικας: Επιλογή όλων
/* FILE: libop.h */
#ifndef LIBOP_H /* Protect against multiple inclusions of this file */
#define LIBOP_H
/* LIBOP inclusions of standard header files */
#include <limits.h>
#include <float.h>
#include <math.h>
/* LIBOP Constants & Macros */
enum {
OP_ADD = '+',
OP_SUB = '-',
OP_MUL = '*',
OP_DIV = '/',
OP_MOD = '%',
};
#define OP_INT_ISERROR(n) ( (n) == INT_MIN )
#define OP_LONG_ISERROR(l) ( (l) == LONG_MIN )
#define OP_FLT_ISERROR(f) ( (f) == FLT_MIN )
#define OP_DBL_ISERROR(d) ( (d) == DBL_MIN )
#define OP_FLT_ZEROMARGIN 0.0000000000000001
#define OP_FLT_ISZERO(f) ( fabsf((f)) < OP_FLT_ZEROMARGIN )
#define OP_DBL_ZEROMARGIN 0.000000000000000000000000000001
#define OP_DBL_ISZERO(d) ( fabs((d)) < OP_DBL_ZEROMARGIN )
/* LIBOP Function Prototypes */
extern int opInt( const char op, const int x, const int y );
extern long int opLong( const char op, const long int x, const long int y );
extern float opFloat( const char op, const float x, const float y );
extern double opDouble( const char op, const double x, const double y );
#endif /* #ifndef LIBOP_H */
- Κώδικας: Επιλογή όλων
/* FILE: libop.c */
#include "libop.h "
/*********************************************************//**
*
************************************************************/
int opInt( const char op, const int x, const int y )
{
int ret = INT_MIN;
if ( op == OP_ADD )
ret = x + y;
else if ( op == OP_SUB )
ret = x - y;
else if ( op == OP_MUL )
ret = x * y;
else if ( op == OP_DIV )
ret = (y == 0) ? INT_MIN : x / y;
else if ( op == OP_MOD )
ret = (y == 0) ? INT_MIN : x % y;
return ret;
}
/*********************************************************//**
*
************************************************************/
long int opLong( const char op, const long x, const long y )
{
long int ret = LONG_MIN;
if ( op == OP_ADD )
ret = x + y;
else if ( op == OP_SUB )
ret = x - y;
else if ( op == OP_MUL )
ret = x * y;
else if ( op == OP_DIV )
ret = (y == 0) ? LONG_MIN : x / y;
else if ( op == OP_MOD )
ret = (y == 0) ? LONG_MIN : x % y;
return ret;
}
/*********************************************************//**
*
************************************************************/
float opFloat( const char op, const float x, const float y )
{
float ret = FLT_MIN;
if ( op == OP_ADD )
ret = x + y;
else if ( op == OP_SUB )
ret = x - y;
else if ( op == OP_MUL )
ret = x * y;
else if ( op == OP_DIV )
ret = OP_FLT_ISZERO(y) ? FLT_MIN : x / y;
else if ( op == OP_MOD )
ret = OP_FLT_ISZERO(y) ? FLT_MIN : fmodf(x,y);
return ret;
}
/*********************************************************//**
*
************************************************************/
double opDouble( const char op, const double x, const double y )
{
double ret = DBL_MIN;
if ( op == OP_ADD )
ret = x + y;
else if ( op == OP_SUB )
ret = x - y;
else if ( op == OP_MUL )
ret = x * y;
else if ( op == OP_DIV )
ret = OP_DBL_ISZERO(y) ? DBL_MIN : x / y;
else if ( op == OP_MOD )
ret = OP_DBL_ISZERO(y) ? DBL_MIN : fmod(x,y);
return ret;
}
Τα παραπάνω είναι τα της βιβλιοθήκης (btw, δες πως διαχειριζόμαστε ισότητες με το 0.0 όταν έχουμε floating ή double μεταβλητές). Για να πάρεις το .o αρχείο της κάνεις...
- Κώδικας: Επιλογή όλων
gcc -c libop.c
Κι εδώ το δοκιμαστικό πρόγραμμα (μου βγήκε λίγο μπερδεμένο, επειδή το έκανα βιαστικά... ευελπιστώ να βοηθήσιε πάντως).
- Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <stdlib.h>
#include "libop.h"
#define MAXINPUT (255+1)
#define pressENTER() \
do{ \
char mYcHAr; \
printf( "press ENTER..." ); \
while ( (mYcHAr=getchar()) != '\n' && mYcHAr != EOF ) \
; \
}while(0)
/*********************************************************//**
*
************************************************************/
char menu1( void )
{
char input[ MAXINPUT ] = {'\0'};
puts( "\nSelect type of data" );
puts( "\ti for int\n\tl for long\n\tf for float\n\td for double\n\tx to exit");
printf( "> " );
if ( NULL == fgets( input, MAXINPUT, stdin ) ) {
fputs("*** fatal error, exiting the program...\n", stderr );
return 'x';
}
return *input;
}
/*********************************************************//**
*
************************************************************/
int menu2( char *input )
{
if ( !input ) {
fputs("*** internal error, exiting the program...\n", stderr );
return 0; /* false */
}
puts( "\nEnter operation & operands (leave spaces)" );
puts( "\t+ x y \t for adding x and y");
puts( "\t- x y \t for subtracting y from x");
puts( "\t* x y \t for multiplying x with y");
puts( "\t/ x y \t for dividing x by y");
puts( "\t% x y \t for the remainder of division x / y");
puts( "\tx \t to exit the program");
printf( "> " );
if ( NULL == fgets( input, MAXINPUT, stdin ) ) {
fputs("*** fatal error, exiting the program...\n", stderr );
return 0;
}
return 1; /* true */
}
/*********************************************************//**
*
************************************************************/
void do_int( const char *input )
{
char op = '\0';
int res, x, y;
if ( !input || !*input)
return;
sscanf( input, "%c %d %d", &op, &x, &y );
res = opInt( op, x, y );
if ( op == 'x' )
return;
if ( OP_INT_ISERROR(res) )
fputs( "*** an error occured, try again...\n", stderr );
else
printf("(int) result = %d\n", res );
pressENTER();
return;
}
/*********************************************************//**
*
************************************************************/
void do_long( const char *input )
{
char op = '\0';
long int res, x, y;
if ( !input || !*input)
return;
sscanf( input, "%c %ld %ld", &op, &x, &y );
res = opLong( op, x, y );
if ( op == 'x' )
return;
if ( OP_LONG_ISERROR(res) )
fputs( "*** an error occured, try again...\n", stderr );
else
printf("(long int) result = %ld\n", res );
pressENTER();
return;
}
/*********************************************************//**
*
************************************************************/
void do_float( const char *input )
{
char op = '\0';
float res, x, y;
if ( !input || !*input)
return;
sscanf( input, "%c %f %f", &op, &x, &y );
res = opFloat( op, x, y );
if ( op == 'x' )
return;
if ( OP_FLT_ISERROR(res) )
fputs( "*** an error occured, try again...\n", stderr );
else
printf("(float) result = %f\n", res );
pressENTER();
return;
}
/*********************************************************//**
*
************************************************************/
void do_double( const char *input )
{
char op = '\0';
double res, x, y;
if ( !input || !*input)
return;
sscanf( input, "%c %lf %lf", &op, &x, &y );
res = opDouble( op, x, y );
if ( op == 'x' )
return;
if ( OP_DBL_ISERROR(res) )
fputs( "*** an error occured, try again...\n", stderr );
else
printf("(double) result = %g\n", res );
pressENTER();
return;
}
/*********************************************************//**
*
************************************************************/
int main( void )
{
char c = '\0';
char input[ MAXINPUT ] = {'\0'};
do {
c = menu1();
if ( c == 'x' )
break;
} while ( c != 'i' && c != 'l' && c != 'f' && c != 'd');
if ( c == 'x')
exit( EXIT_SUCCESS );
while ( *input != 'x' && menu2(input) )
{
if ( c == 'i' )
do_int( input );
else if ( c == 'l' )
do_long( input );
else if ( c == 'f' )
do_float( input );
else if ( c == 'd' )
do_double( input );
}
exit( EXIT_SUCCESS );
}
στο οποίο προσθέτεις το .o της βιβλιοθήκης στη γραμμή εντολών του gcc...
- Κώδικας: Επιλογή όλων
gcc test.c libop.o -o test
./test





