taslikos Δημοσ. 14 Μαρτίου 2017 Δημοσ. 14 Μαρτίου 2017 Καλημέρες στην κοινότητα, Είμαι νέος στην c και έχω γράψει ένα προγραμμα που κάνει μια συγκεκριμένη δουλειά. Θα ήθελα καθώς αρχίζει το προγραμμα να βγάζει μήνυμα press 1 to run the program or 0 to stop it. Μετά έχω βάλει ένα while loop το οποίο τρέχει μόνο όταν η είσοδος είναι 1 όμως τρέχει μόνο μια φορά. Έχω βάλει και στο τέλος του while πάλι να ξαναδιαβάζει την είσοδο 0 or 1 αλλά δεν τρέχει κ ξανά. Καμία ιδέα;
Moderators Kercyn Δημοσ. 14 Μαρτίου 2017 Moderators Δημοσ. 14 Μαρτίου 2017 Για βάλε κώδικα να δούμε. 1
NickSym Δημοσ. 14 Μαρτίου 2017 Δημοσ. 14 Μαρτίου 2017 Καλημέρες στην κοινότητα, Είμαι νέος στην c και έχω γράψει ένα προγραμμα που κάνει μια συγκεκριμένη δουλειά. Θα ήθελα καθώς αρχίζει το προγραμμα να βγάζει μήνυμα press 1 to run the program or 0 to stop it. Μετά έχω βάλει ένα while loop το οποίο τρέχει μόνο όταν η είσοδος είναι 1 όμως τρέχει μόνο μια φορά. Έχω βάλει και στο τέλος του while πάλι να ξαναδιαβάζει την είσοδο 0 or 1 αλλά δεν τρέχει κ ξανά. Καμία ιδέα; Δείξε μας τον κώδικα σου για να σε βοηθήσουμε επακριβώς.. Αλλά επειδή φαντάζομαι τι παίζει, όταν διαβάζεις μόνο έναν χαρακτήρα διάβαζε τον με την getchar κι όχι με την scanf ή όταν χρησιμοποιείς την scanf να έχεις ένα κενό πριν το %c. Δηλαδή scanf(" %c", &c); 1
taslikos Δημοσ. 14 Μαρτίου 2017 Μέλος Δημοσ. 14 Μαρτίου 2017 #include <stdio.h> #include <stdlib.h> void s1(int d); void s2(int n); void s3(int n); void s4(int d); void s5(int d); void s6(int n); int main() { int w,t,e; printf("Press 1 to start the program or 0 to stop it: "); scanf("%d",&e); while(e==1){ printf("Type: \n 1 for s1 \n 2 for s2 \n 3 for s3 \n 4 for s4 \n 5 for s5 \n 6 for s6 \n"); scanf("%d", &t); printf("Enter value: "); scanf("%d",&w); if(t==1){ s1(w); } if(t==2){ s2(w); } if(t==3){ s3(w); } if (t==4){ s4(w); } if(t==5){ s5(w); } if(t==6){ s6(w); } printf("\n"); printf("Press 1 to start the program or 0 to stop it: "); scanf("%d",&e); return 0; } } void s1(int d){} void s2(int n){} void s3(int n){} void s4(int n){} void s5(int d){} void s6(int n){} για να μην το κανω πολύπλοκο ονομασα s1... τις συναρτησεις και δεν σας βαζω την λειτουργια τους διοτι αυτες τρεχουν σωστα Δείξε μας τον κώδικα σου για να σε βοηθήσουμε επακριβώς.. Αλλά επειδή φαντάζομαι τι παίζει, όταν διαβάζεις μόνο έναν χαρακτήρα διάβαζε τον με την getchar κι όχι με την scanf ή όταν χρησιμοποιείς την scanf να έχεις ένα κενό πριν το %c. Δηλαδή scanf(" %c", &c); οχι αυτο το γνωριζω και δεν εκανα τετοιο λαθος ακυρο παιδες το βρηκα ηταν το } στο τελος επρεπε να παει πριν το return 0; ευχαριστω
BabyRage Δημοσ. 14 Μαρτίου 2017 Δημοσ. 14 Μαρτίου 2017 Είναι εντυπωσιακό πως καμία φορά όταν ποστάρεις τον buggy κώδικα κάπου για να τον εξηγήσεις σε κάποιον βρίσκεις το λάθος... https://en.wikipedia.org/wiki/Rubber_duck_debugging
k33theod Δημοσ. 14 Μαρτίου 2017 Δημοσ. 14 Μαρτίου 2017 Γενική παρατήρηση αν επιτρέπεις Όταν κάτι λειτουργεί σαν διακόπτης όπως το t δεν πρέπει να χρησιμοποιείς if άλλα if , else if ή switch Επίσης το σκεπτικό για printf("Press 1 to start the program or 0 to stop it: "); scanf("%d",&e); είναι λάθος γιατί στην ουσία εκτελείς το πρόγραμμα μόνο όταν e==1 και βγαίνει σε κάθε άλλη περίπτωση 0,2,3,4 κλπ 1
Lum1nous Δημοσ. 14 Μαρτίου 2017 Δημοσ. 14 Μαρτίου 2017 Αν και δεν εχω ιδεα απο σωστο , επαγγελματικο προγραμματισμο : Προσωπικα με βολευει σε τετοια προβληματα να βαζω στην while μια παντα αληθη συνθηκη π.χ while(1) και μετα θα βαζα ενα if (e == 0 ) { break ; } 1
imitheos Δημοσ. 15 Μαρτίου 2017 Δημοσ. 15 Μαρτίου 2017 Όπως είπανε και τα άλλα παιδιά, μια και η επιλογή γίνεται με βάση μια ακέραια τιμή, είναι πιο εύκολο να το γράψεις με ένα switch αντί για 300 if. Μια και λύθηκε η απορία του OP, ένας άλλος τρόπος με τον οποίο μπορεί να υλοποιηθεί είναι με πίνακα από δείκτες συναρτήσεων. Σίγουρα είναι πάρα πολύ προσωρημένο για την συγκεκριμένη άσκηση αλλά το αναφέρω απλά σαν παράδειγμα και για τον OP και για κάποιον άλλον που θα διαβάσει το νήμα. Εφόσον λοιπόν οι συναρτήσεις μας έχουν τα ίδια ορίσματα και ίδιο τύπο επιστροφής, τότε μπορούμε να χρησιμοποιήσουμε ένα πίνακα από δείκτες συναρτήσεων. Έτσι ο κώδικας είναι πιο όμορφος, πιο γρήγορος ( α) σε σχέση με τα if όχι με το switch, β) πρακτικά δεν θα δεις διαφορά), και πιο scalable αν αύριο προστεθούν νέες συναρτήσεις. .... μπλα μπλα .... void s6(int d); // Για να βρούμε τον τύπο μιας μεταβλητής ξεκινούμε από το όνομα // και πηγαίνουμε πάντα δεξιά, μέχρι το σημείο που δεν μπορούμε // να πάμε άλλο οπότε πηγαίνουμε αριστερά. // Ξεκινάμε λοιπόν από το fpt και πηγαίνουμε δεξιά οπότε παίρνουμε // ότι το fpt είναι πίνακας 6 θέσεων // Έπειτα υπάρχει παρένθεση οπότε πηγαίνουμε αριστερά και παίρνουμε // δείκτη οπότε το fpt για την ώρα είναι πίνακας 6 θέσεων με στοιχεία δείκτες // Τελείωσε η παρένθεση οπότε πάμε πάλι δεξιά και παίρνουμε (int d) // οπότε έχουμε συνάρτηση με όρισμα ένα ακέραιο. Δεξιά δεν πάει άλλο // Πηγαίνουμε αριστερά και παίρνουμε void // Έτσι λοιπόν το fpt είναι ένας πίνακας 6 θέσεων με στοιχεία δείκτες // σε συναρτήσεις που παίρνουν όρισμα ακέραιο και δεν επιστρέφουν τίποτα. // Δηλαδή ακριβώς αυτό που είναι οι sX συναρτήσεις μας. // Για να συνθέσω την δήλωση του fpt, έκανα στο μυαλό μου την αντίστροφη // διαδικασία και προέκυψε το "void (*fpt[6])(int d)" // Έπειτα απλά θέτουμε ως τιμές τις διευθύνσεις των συναρτήσεων μας // (τα & μπορούν να παραληφθούν αν θέλουμε) static void (*fpt[6])(int d) = { &s1, &s2, &s3, &s4, &s5, &s6 }; int main(void) { ... μπλα μπλα ... printf("Type: \n 1 for s1 \n 2 for s2 \n 3 for s3 \n 4 for s4 \n 5 for s5 \n 6 for s6 \n"); scanf("%d", &t); printf("Enter value: "); scanf("%d",&w); fpt[t - 1](w); Τρέχουμε την συνάρτηση που βρίσκεται στην θέση t - 1 (επειδή η αρίθμηση στον πίνακα αρχίζει από το 0 οπότε η s1 βρίσκεται στην θέση 0) με όρισμα w με απλό και ευανάγνωστο τρόπο χωρίς 300 if - else. Φυσικά, ο κώδικάς μας θα έπρεπε να έχει 15 ελέγχους εδώ και εκεί απλά για να είναι κατανοητό το παράδειγμα έγραψα τον ελάχιστο δυνατό κώδικα. 6
defacer Δημοσ. 15 Μαρτίου 2017 Δημοσ. 15 Μαρτίου 2017 Μια και λύθηκε η απορία του OP, ένας άλλος τρόπος με τον οποίο μπορεί να υλοποιηθεί είναι με πίνακα από δείκτες συναρτήσεων. Σίγουρα είναι πάρα πολύ προσωρημένο για την συγκεκριμένη άσκηση αλλά το αναφέρω απλά σαν παράδειγμα και για τον OP και για κάποιον άλλον που θα διαβάσει το νήμα. Αυτό σκεφτόμουν όταν είδα τον κώδικα, αλλά τεμπέλης. ΥΓ το καλύτερο abuse που έχω δει σχετικά.
taslikos Δημοσ. 15 Μαρτίου 2017 Μέλος Δημοσ. 15 Μαρτίου 2017 Γενική παρατήρηση αν επιτρέπεις Όταν κάτι λειτουργεί σαν διακόπτης όπως το t δεν πρέπει να χρησιμοποιείς if άλλα if , else if ή switch Επίσης το σκεπτικό για printf("Press 1 to start the program or 0 to stop it: "); scanf("%d",&e); είναι λάθος γιατί στην ουσία εκτελείς το πρόγραμμα μόνο όταν e==1 και βγαίνει σε κάθε άλλη περίπτωση 0,2,3,4 κλπ Έρχομαι από python και το είχα παρατηρήσει και εκεί αλλά στην python πάντα δεν έτρεχε σωστά στους ελέγχους μου και τότε μόνο το άλλαζα με elif μετά από ένα σημείο έμαθα να την χρησιμοποιώ σωστά και εκεί. Κατάλαβα την χρήση της και στην c αν δεν κάνω λάθος είναι ίδια και έτσι είμαι πιο εξοικειωμένος. Ευχαριστώ για την βοήθεια.Είναι εντυπωσιακό πως καμία φορά όταν ποστάρεις τον buggy κώδικα κάπου για να τον εξηγήσεις σε κάποιον βρίσκεις το λάθος... https://en.wikipedia.org/wiki/Rubber_duck_debuggingΠράγματι εντυπωσιακό και όντως δουλεύει τελικά Όπως είπανε και τα άλλα παιδιά, μια και η επιλογή γίνεται με βάση μια ακέραια τιμή, είναι πιο εύκολο να το γράψεις με ένα switch αντί για 300 if. Μια και λύθηκε η απορία του OP, ένας άλλος τρόπος με τον οποίο μπορεί να υλοποιηθεί είναι με πίνακα από δείκτες συναρτήσεων. Σίγουρα είναι πάρα πολύ προσωρημένο για την συγκεκριμένη άσκηση αλλά το αναφέρω απλά σαν παράδειγμα και για τον OP και για κάποιον άλλον που θα διαβάσει το νήμα. Εφόσον λοιπόν οι συναρτήσεις μας έχουν τα ίδια ορίσματα και ίδιο τύπο επιστροφής, τότε μπορούμε να χρησιμοποιήσουμε ένα πίνακα από δείκτες συναρτήσεων. Έτσι ο κώδικας είναι πιο όμορφος, πιο γρήγορος ( α) σε σχέση με τα if όχι με το switch, β) πρακτικά δεν θα δεις διαφορά), και πιο scalable αν αύριο προστεθούν νέες συναρτήσεις. .... μπλα μπλα .... void s6(int d); // Για να βρούμε τον τύπο μιας μεταβλητής ξεκινούμε από το όνομα // και πηγαίνουμε πάντα δεξιά, μέχρι το σημείο που δεν μπορούμε // να πάμε άλλο οπότε πηγαίνουμε αριστερά. // Ξεκινάμε λοιπόν από το fpt και πηγαίνουμε δεξιά οπότε παίρνουμε // ότι το fpt είναι πίνακας 6 θέσεων // Έπειτα υπάρχει παρένθεση οπότε πηγαίνουμε αριστερά και παίρνουμε // δείκτη οπότε το fpt για την ώρα είναι πίνακας 6 θέσεων με στοιχεία δείκτες // Τελείωσε η παρένθεση οπότε πάμε πάλι δεξιά και παίρνουμε (int d) // οπότε έχουμε συνάρτηση με όρισμα ένα ακέραιο. Δεξιά δεν πάει άλλο // Πηγαίνουμε αριστερά και παίρνουμε void // Έτσι λοιπόν το fpt είναι ένας πίνακας 6 θέσεων με στοιχεία δείκτες // σε συναρτήσεις που παίρνουν όρισμα ακέραιο και δεν επιστρέφουν τίποτα. // Δηλαδή ακριβώς αυτό που είναι οι sX συναρτήσεις μας. // Για να συνθέσω την δήλωση του fpt, έκανα στο μυαλό μου την αντίστροφη // διαδικασία και προέκυψε το "void (*fpt[6])(int d)" // Έπειτα απλά θέτουμε ως τιμές τις διευθύνσεις των συναρτήσεων μας // (τα & μπορούν να παραληφθούν αν θέλουμε) static void (*fpt[6])(int d) = { &s1, &s2, &s3, &s4, &s5, &s6 }; int main(void) { ... μπλα μπλα ... printf("Type: \n 1 for s1 \n 2 for s2 \n 3 for s3 \n 4 for s4 \n 5 for s5 \n 6 for s6 \n"); scanf("%d", &t); printf("Enter value: "); scanf("%d",&w); fpt[t - 1](w); Τρέχουμε την συνάρτηση που βρίσκεται στην θέση t - 1 (επειδή η αρίθμηση στον πίνακα αρχίζει από το 0 οπότε η s1 βρίσκεται στην θέση 0) με όρισμα w με απλό και ευανάγνωστο τρόπο χωρίς 300 if - else. Φυσικά, ο κώδικάς μας θα έπρεπε να έχει 15 ελέγχους εδώ και εκεί απλά για να είναι κατανοητό το παράδειγμα έγραψα τον ελάχιστο δυνατό κώδικα. Δεν γνωρίζω ακόμη πίνακες καλά, σε ευχαριστώ για την ιδέα σου θα την μελετήσω
k33theod Δημοσ. 15 Μαρτίου 2017 Δημοσ. 15 Μαρτίου 2017 η λογική είναι η ίδια στα nested ifs δηλαδή if elif .... else, όταν κάτι είναι true ο έλεγχος φεύγει και πάει μετά το else. Όπως το έχεις στον κώδικα σου θα ελεγχθούν όλα τα if. Μαθαίνεις με κάποιο βιβλίο, εγώ έχω το c programming a modern approach. Είμαι πιστεύω στο ίδιο επίπεδο με σένα αν και είδα και τις λίστες . Έχοντας και εγώ αρκετή επαφή με την python η c μου φαίνεται σαν να γράφτηκε 200 χρόνια πριν. Διαβάζω 2 μήνες και ακόμα printf, scanf και τίποτα από modern approach.
_Gikoskos_ Δημοσ. 16 Μαρτίου 2017 Δημοσ. 16 Μαρτίου 2017 Έχοντας και εγώ αρκετή επαφή με την python η c μου φαίνεται σαν να γράφτηκε 200 χρόνια πριν. Διαβάζω 2 μήνες και ακόμα printf, scanf και τίποτα από modern approach. Εχεις δικιο σε αυτο, ειναι καπως αργο το payoff της C. Κατι που σιγουρα θα βοηθησει αρκετα (γενικα βοηθαει αν θες να μαθεις οποιαδηποτε γλωσσα, οχι μονο την C) ειναι να θεσεις εναν συγκεκριμενο στοχο. Μια εφαρμογη που θελεις να φτιαξεις με την γλωσσα, κατι που θες να δημιουργησεις απο το 0 τελος παντων. Δεν χρειαζεται να ειναι κατι περιπλοκο για αρχη. Θα μπορουσε να ειναι sudoku solver, AI για τριλιζα, command line σκακι, chatting μεταξυ δυο διαφορετικων διεργασιων, φιδακι, διερμηνεας (το αγαπημενο μου, προσωπικα), απλος text editor για το command line, pong, tetris κτλ κτλ Γενικα αν εχεις κατι που χρειαζεσαι εσυ να φτιαξεις, κατι που δεν σε αφηνει να κοιμασαι τα βραδια, κατι που θες να κατσεις και να γραψεις για να το βγαλεις απο μεσα σου. Αυτο ειχε βοηθησει τουλαχιστον εμενα οταν τα μαθαινα, αλλα ειμαι σιγουρος πως η ιδια λογικη θα βοηθησει και πολλους αλλους. .... μπλα μπλα .... void s6(int d); // Για να βρούμε τον τύπο μιας μεταβλητής ξεκινούμε από το όνομα // και πηγαίνουμε πάντα δεξιά, μέχρι το σημείο που δεν μπορούμε // να πάμε άλλο οπότε πηγαίνουμε αριστερά. // Ξεκινάμε λοιπόν από το fpt και πηγαίνουμε δεξιά οπότε παίρνουμε // ότι το fpt είναι πίνακας 6 θέσεων // Έπειτα υπάρχει παρένθεση οπότε πηγαίνουμε αριστερά και παίρνουμε // δείκτη οπότε το fpt για την ώρα είναι πίνακας 6 θέσεων με στοιχεία δείκτες // Τελείωσε η παρένθεση οπότε πάμε πάλι δεξιά και παίρνουμε (int d) // οπότε έχουμε συνάρτηση με όρισμα ένα ακέραιο. Δεξιά δεν πάει άλλο // Πηγαίνουμε αριστερά και παίρνουμε void // Έτσι λοιπόν το fpt είναι ένας πίνακας 6 θέσεων με στοιχεία δείκτες // σε συναρτήσεις που παίρνουν όρισμα ακέραιο και δεν επιστρέφουν τίποτα. // Δηλαδή ακριβώς αυτό που είναι οι sX συναρτήσεις μας. // Για να συνθέσω την δήλωση του fpt, έκανα στο μυαλό μου την αντίστροφη // διαδικασία και προέκυψε το "void (*fpt[6])(int d)" // Έπειτα απλά θέτουμε ως τιμές τις διευθύνσεις των συναρτήσεων μας // (τα & μπορούν να παραληφθούν αν θέλουμε) static void (*fpt[6])(int d) = { &s1, &s2, &s3, &s4, &s5, &s6 }; int main(void) { ... μπλα μπλα ... printf("Type: \n 1 for s1 \n 2 for s2 \n 3 for s3 \n 4 for s4 \n 5 for s5 \n 6 for s6 \n"); scanf("%d", &t); printf("Enter value: "); scanf("%d",&w); fpt[t - 1](w); Τρέχουμε την συνάρτηση που βρίσκεται στην θέση t - 1 (επειδή η αρίθμηση στον πίνακα αρχίζει από το 0 οπότε η s1 βρίσκεται στην θέση 0) με όρισμα w με απλό και ευανάγνωστο τρόπο χωρίς 300 if - else. Φυσικά, ο κώδικάς μας θα έπρεπε να έχει 15 ελέγχους εδώ και εκεί απλά για να είναι κατανοητό το παράδειγμα έγραψα τον ελάχιστο δυνατό κώδικα. Το οτι θα εβλεπα εδω jump tables στην C, ποτε δεν θα το περιμενα μπραβο σου Καποιες παρατηρησεις και απο την δικη μου εμπειρια. Αρχικα, κατα πασα πιθανοτητα ο compiler θα μετατρεψει ακομα και το switch/case στον παραπανω κωδικα σε jump table (απο -O2 και πανω συνηθως αλλα αυτο ειναι αναλογως του compiler), δηλαδη δεν χρειαζεται να κατσεις να κανεις hardcode το jump table σου (premature optimization is the root of all evil κτλ κτλ). Επισης δεν ειναι απαραιτητο να εχεις ελεγχους για να μην ξεπερασεις το μεγεθος του πινακα σε περιπτωση που ο χρηστης δωσει κακο input (αγνοωντας τους ελεγχους της scanf εννοειται). Απλα μπορεις να γραψεις αυτο: fpt[(t - 1)%6](w); και ετσι, καθε input που δινει ο χρηστης ειναι εγκυρο. Αν το t ειναι προσημασμενος ακεραιος βεβαια θα πρεπει να λαβεις υποψη και περιπτωσεις οπου το t ειναι αρνητικος. Κατι τετοιο, πιστευω, μπορει να τις πιασει ολες: fpt[( ( (t - 1)%6 ) + 6 ) % 6](w); (σημειωση πως αν θες πχ το index [-3] να σε παει στην θεση [3], τοτε αν δινει εισοδους ο χρηστης απο 1 εως 6 δεν γινεται αυτο με τον παραπανω κωδικα. Θα πρεπει να ειναι ετσι δηλαδη fpt[( ( t % 6 ) + 6 ) % 6](w); οπου το t ειναι απο -5 εως 5, και οποιαδηποτε αλλη τιμη απλα σε βγαζει στην θεση που ειναι t modulo 6) Αυτο βεβαια ειναι αν θες να εκτελεις μια function απο το jump table σου, ειτε δωσει σωστο input ο χρηστης ειτε οχι. Αν θες να μην εκτελεις κανενα function σε περιπτωση bad input μαλλον δεν το γλιτωνεις το if/else (μπορει να γινεται και αν εχεις ενα stub function μεσα στον πινακα, που δεν κανει απολυτως τιποτα και απλα το καλεις οταν δεν θες να γινει κατι, αλλα δεν το εχω πολυσκεφτει)
imitheos Δημοσ. 16 Μαρτίου 2017 Δημοσ. 16 Μαρτίου 2017 Το οτι θα εβλεπα εδω jump tables στην C, ποτε δεν θα το περιμενα μπραβο σουΓιατί δεν το περίμενες ? Είναι συνήθης η χρήση του στη C (ίσως και λόγω έλλειψης πιο high level υποδομών όπως παρέχουν οι άλλες γλώσσες) Καποιες παρατηρησεις και απο την δικη μου εμπειρια. Αρχικα, κατα πασα πιθανοτητα ο compiler θα μετατρεψει ακομα και το switch/case στον παραπανω κωδικα σε jump table (απο -O2 και πανω συνηθως αλλα αυτο ειναι αναλογως του compiler), δηλαδη δεν χρειαζεται να κατσεις να κανεις hardcode το jump table σου (premature optimization is the root of all evil κτλ κτλ).Φυσικά θα το κάνει για αυτό έγραψα ότι θα είναι μεν πιο γρήγορο από την περίπτωση του if αλλά όχι του switch. Μάλιστα αρχικά ανέφερα ότι ο compiler στις περισσότερες περιπτώσεις θα μετατρέψει το switch σε ακριβώς αυτό και είχα βάλει και την assembly που προκύπτει από τις τρεις περιπτώσεις αλλά ήταν πάρα πολύ πληροφορία (και μάλιστα άχρηστη σε κάποιον που δεν ξέρει assembly για να κρίνει την διαφορά) οπότε το αφαίρεσα και άφησα μόνο το post που διάβασες.
defacer Δημοσ. 16 Μαρτίου 2017 Δημοσ. 16 Μαρτίου 2017 Καποιες παρατηρησεις και απο την δικη μου εμπειρια. Αρχικα, κατα πασα πιθανοτητα ο compiler θα μετατρεψει ακομα και το switch/case στον παραπανω κωδικα σε jump table (απο -O2 και πανω συνηθως αλλα αυτο ειναι αναλογως του compiler), δηλαδη δεν χρειαζεται να κατσεις να κανεις hardcode το jump table σου (premature optimization is the root of all evil κτλ κτλ). Δεν είμαι σίγουρος αν θα γίνει αυτό που λες... όσον αφορά την υλοποίηση του switch τότε ναι υπό συνθήκες (δεν ξέρω ακριβώς πώς πάει ανα compiler και optimization level) θα γίνει αυτόματα με jump table, αλλά σε τι ακριβώς θα κάνει jump το table? Αν δεις τη generated assembly από την "χαζή" εκδοχή του προγράμματος με switch, τόσο gcc όσο και clang τελευταίες εκδόσεις με -O3 κάνουν το dispatch σε case με jump table, αλλά το function call (μαζί με το push του ορίσματος) γίνεται manually -- είναι ξεχωριστά instructions σε κάθε περίπτωση (αν και, ο GCC με -Os καταλαβαίνει πως το push του ορίσματος είναι κοινό και το βγάζει έξω από το jump πριν το call). Από την άλλη όταν κάνεις explicitly τον πίνακα του ημίθεου βλέπεις πως το call πλέον μαζεύεται σε ένα μόνο instruction και o compiler δεν κάνει generate απολύτως κανένα jump.
_Gikoskos_ Δημοσ. 16 Μαρτίου 2017 Δημοσ. 16 Μαρτίου 2017 (επεξεργασμένο) Δεν είμαι σίγουρος αν θα γίνει αυτό που λες... όσον αφορά την υλοποίηση του switch τότε ναι υπό συνθήκες (δεν ξέρω ακριβώς πώς πάει ανα compiler και optimization level) θα γίνει αυτόματα με jump table, αλλά σε τι ακριβώς θα κάνει jump το table? Αν δεις τη generated assembly από την "χαζή" εκδοχή του προγράμματος με switch, τόσο gcc όσο και clang τελευταίες εκδόσεις με -O3 κάνουν το dispatch σε case με jump table, αλλά το function call (μαζί με το push του ορίσματος) γίνεται manually -- είναι ξεχωριστά instructions σε κάθε περίπτωση (αν και, ο GCC με -Os καταλαβαίνει πως το push του ορίσματος είναι κοινό και το βγάζει έξω από το jump πριν το call). Από την άλλη όταν κάνεις explicitly τον πίνακα του ημίθεου βλέπεις πως το call πλέον μαζεύεται σε ένα μόνο instruction και o compiler δεν κάνει generate απολύτως κανένα jump. Ετσι ειναι το jump table σε assembly https://godbolt.org/g/JPpnCI Η αντιστοιχη εκδοχη του ημιθεου μαζι με checks (γιατι στην ουσια το switch/case θα μετρησει ολες τις περιπτωσεις, ενω ετσι οπως το εγραψε ο ημιθεος δεν υπολογιζονται ολες οι περιπτωσεις, αρα οι κωδικες που συγκρινες ειναι εντελως διαφορετικοι) θα γινει ετσι https://godbolt.org/g/t6TJFn Γενικα για να πιεσεις τον compiler να κανει fully optimized jump tables, θα πρεπει να γραψεις τις συναρτησεις οπως το εγραψα παραπανω. O optimizer του compiler μια χαρα μπορει να καταλαβει το switch/case και να το μετατρεψει σε jump table. Αν δεις και στο αρχικο μου ποστ τι εγραψα: Το οτι θα εβλεπα εδω jump tables στην C, ποτε δεν θα το περιμενα Αυτο που υλοποιησε ο hmitheos ειναι καθαρα jump table στην C. Οχι σε assembly. Αυτο ειναι optimization μονο σε higher level C και οχι σε assembly. Τα optimizations που κανουμε σε υψηλο επιπεδο, δεν σημαινει πως μεταφραζονται παντα σε optimizations στο χαμηλο. Πολλες φορες ο προγραμματιστης δεν μπορει να καταλαβει πως ακριβως λειτουργει η μηχανη. Τωρα το πιο optimization ειναι πιο γρηγορο ή οχι, ειναι αντικειμενο ακαδημαϊκης μελετης. Κατα την γνωμη μου, και τα δυο ειναι εξισου σωστα. Καποιος μπορει να πει πως το switch/case ειναι πιο ευαναγνωστο και καποιος αλλος μπορει να πει πως το C jump table ειναι πιο γρηγορο να το γραψεις (και επισης το τελικο εκτελεσιμο εχει μονο ενα call instruction, και ως συνεπεια ειναι λιγοτερα bytes απο το switch/case). Εδιτ: ειχα λαθος στους προηγουμενους κωδικες που ποσταρα. Thanks στον defacer που το παρατηρησε Επεξ/σία 16 Μαρτίου 2017 από _Gikoskos_
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα