geomagas Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Δεν υπάρχει λόγος να κάνει τέτοια πράγματα. Much cleaner να γίνουν όλα με ένα απλό while (bytesToSend): uint8_t* data = bigBuffer /* ή κάτι τέτοιο */ int bytesToSend = 500; while (bytesToSend) { int batchSize = std::min(bytesToSend, 64); send(data, batchSize); bytesToSend -= batchSize; } Το να αντικαταστήσει κανείς ένα απλό min() με έξτρα πράξεις και έξτρα μία επανάληψη στο τέλος είναι το είδος του κώδικα που γράφει κανείς όταν μόλις μαθαίνει. Επιπλέον, αν τύχει ο αριθμός που θέλεις να στείλεις να είναι ακέραιο πολλαπλάσιο του π.χ. 64 τότε έτσι που το έχετε θα κάνει ένα ακόμα send με μήκος μηδέν, το οποίο μπορεί πολύ άνετα να μην επιτρέπεται (δεν έχουμε ιδέα τι κάνει αυτή η send). Simple is good. Τώρα εγώ που γηράσκω αεί διδασκόμενος (και το ξέρω!), νομίζω ότι αυτό θα στέλνει πάντα τα πρώτα min(bytesToSend, 64) του bigBuffer. Κάνω λάθος; 2
migf1 Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Εφόσον επί της ουσίας το να κάνεις π.x. hardcode κάτι είναι ίδιο με το να το περνάς σαν παράμετρο, οι δυο πρακτικές είναι το ίδιο καλές. Κι εφόσον επί της ουσίας το copy paste είναι το ίδιο με το να κάνεις function, το ίδιο καλό είναι και το copy paste. Παρόλο που δεν έχω καμία αντίρρηση στο να χαρακτηρίσεις τον κώδικά μου κακό (δεν τον έγραψα δα και για να πάρει βραβείο), δεν πάει έτσι. Στην 1η παράγραφο δεν καταλαβαίνω τι εννοείς. Ο κώδικάς σου είναι σαφώς καλύτερος σε readability από τον δικό μου (ούτε εγώ τον έγραψα για βραβείο, έγραψα ότι μου ήρθε εκείνη την ώρα χτες τα μεσάνυχτα και το επισήμανα κιόλας) αλλά και οι 2 κώδικες είναι εξίσου κακοί από efficient pov. Επίσης ο δικός σου δεν είναι C. Συγκριτικά με του πάπι, οι δυο δικοί μας κώδικες δουλεύουν είτε αυτόνομα είτε μέσα σε συνάρτηση (αν δλδ εσύ διορθώσεις εκείνο το min και είτε το γράψεις με ternary μέσα στο loop, είτε το κάνεις ξεχωριστή συνάρτηση/macro). Όμως με μια μικρή προσθήκη στον κώδικα του πάπι (συγκεκριμένα την 1η γραμμή του δικού σου) εξαλείφεται αυτό το μειονέκτημα (αν είναι μειονέκτημα). Οπότε, με αυτή την προσθήκη ο κώδικας γίνεται ιδανικός διότι συνδυάζει efficiency, readability, και applicability... uin8_t *data = buf; int len = 500; int frags = len / 64; for (int i=0; i < frags; i++) { send( data, 64 ); data += 64; } send( data, len % 64 ); Το ξέρω πως σου είναι αδύνατον να δεχτείς κάτι το δικό σου ως κατώτερο οποιουδήποτε άλλου, αλλά δεν πειράζει... όλοι θα ζήσουμε
παπι Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Τώρα εγώ που γηράσκω αεί διδασκόμενος (και το ξέρω!), νομίζω ότι αυτό θα στέλνει πάντα τα πρώτα min(bytesToSend, 64) του bigBuffer. Κάνω λάθος; Α ρε νουμπα defacer 1
migf1 Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Τώρα εγώ που γηράσκω αεί διδασκόμενος (και το ξέρω!), νομίζω ότι αυτό θα στέλνει πάντα τα πρώτα min(bytesToSend, 64) του bigBuffer. Κάνω λάθος; Γεια σου ρε τσάκαλε! Ευτυχώς που συγκαταλέγομαι κι εγώ ανάμεσα σε αυτούς που ακόμα μαθαίνουν (και θα μαθαίνουν)
defacer Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Τώρα εγώ που γηράσκω αεί διδασκόμενος (και το ξέρω!), νομίζω ότι αυτό θα στέλνει πάντα τα πρώτα min(bytesToSend, 64) του bigBuffer. Κάνω λάθος; Nope. Θυμήθηκα να βάλω ξεχωριστή μεταβλητή data αλλά ξέχασα να την αυξήσω. Παπί δείξε λίγη κατανόηση η μνήμη σιγά σιγά εγκαταλείπει. migf1 ξέχασες ότι η άλλη εναλλακτική έχει και καλύτερο γαμικability. Νόμιζα ότι είπα γιατί θεωρώ το while (bytesToSend) καλύτερο σε απλά ελληνικά κατανοητά από οποιονδήποτε, αλλά όπως φαίνεται έκανα λάθος.
imitheos Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Όμως με μια μικρή προσθήκη στον κώδικα του πάπι (συγκεκριμένα την 1η γραμμή του δικού σου) εξαλείφεται αυτό το μειονέκτημα (αν είναι μειονέκτημα). Οπότε, με αυτή την προσθήκη ο κώδικας γίνεται ιδανικός διότι συνδυάζει efficiency, readability, και applicability... uin8_t *data = buf; int len = 500; int frags = len / 64; for (int i=0; i < frags; i++) { send( data, 64 ); data += 64; } send( data, len % 64 ); Το ξέρω πως σου είναι αδύνατον να δεχτείς κάτι το δικό σου ως κατώτερο οποιουδήποτε άλλου, αλλά δεν πειράζει... όλοι θα ζήσουμε Από άποψη απόδοσης και οι δύο κώδικες είναι μια χαρά αλλά από readability δεν νομίζω ότι είναι κατώτερος αυτός του defacer (παραβλέποντας το λάθος με την αύξηση του data). Εννοείται πως και ο δικός σου κώδικας είναι πάρα πολύ εύκολος στην ανάγνωση αλλά ο κώδικας του defacer περνάει πιο σωστά το μήνυμα. Ο δικός σου διαιρεί με το μέγεθος και μετά τρέχει το for. Το αποτέλεσμα είναι μεν το ίδιο αλλά το for είναι συνδυασμένο με ανακύκλωση με γνωστό αριθμό βημάτων. while (μένουν bytes) { κάνε δουλειά. αύξησε buf pointer μείωσε bytes που έμειναν. } Το παραπάνω στυλ που είναι σαν τον κώδικα που έδωσε ο defacer περνάει καθαρά το μήνυμα ότι δεν σε νοιάζει (ή δεν ξέρεις) πόσα βήματα θα κάνεις και απλά δουλεύεις για όσο έχεις bytes. Αν δεις οδηγούς που μιλάνε για sockets, streams, serial programming, κτλ, αυτό το στυλ με το while είναι αυτό που προτείνεται από τους περισσότερους ως το πιο readable. Πρακτικά βέβαια και με for και με while είναι μια χαρά.
migf1 Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Τώρα εγώ που γηράσκω αεί διδασκόμενος (και το ξέρω!), νομίζω ότι αυτό θα στέλνει πάντα τα πρώτα min(bytesToSend, 64) του bigBuffer. Κάνω λάθος; Και μιας και με έβαλες στο τριπάκι να το ψάξω κι άλλο, τόσο ο κώδικας του defacer (είτε βάλει την αύξηση που ξέχασε είτε όχι) όσο και του πάπι, παίρνουν ως δεδομένο len το συνολικό μήκος του buf, παρόλο που ο ts έκανε σαφές πως μπορεί να ΜΗΝ είναι γεμάτο. Και ακριβώς αυτός είναι ο λόγος που εγώ διαχώρισα στον δικό μου κώδικα με διαφορετικά constants το BUF_SIZE από το BUF_DATALEN (με comment πως το 2ο πρέπει να είναι <= του 1ου) και για τον ίδιο λόγο περνάω στη λούπα το BUF_DATALEN και όχι το BUF_SIZE. Και το επισημαίνω ξανά, γιατί όταν το επισήμανα στον ts να το προσέξει (στο ποστ μου με τα sentinel bytes, κλπ) ο defacer απάντησε πως "Δεν υπάρχει λόγος να κάνει τέτοια πράγματα". Και δίνει κώδικα που ακόμα κι αν ήταν C, ακόμα κι αν αύξανε τον data, θα έστελνε στη usb όλα τα σκουπίδια που θα υπάρχουν από buf[bUF_DATALEN] μέχρι buf[bUF_SIZE-1] (αφού εκείνοι δεν κάνουν τέτοιου είδους διαχωρισμό). Αυτό θα ήταν αποδεκτό, μόνο αν η εφαρμογή χρησιμοποιούσε sentinel bytes (κάτι που είναι highly unlikely για binary data) και άρα και η send() μεριμνούσε για sentinel bytes εσωτερικά της. Μπορεί να μεριμνεί μπορεί και όχι, δεν μας το έχει διευκρινίσει ο TS, οπότε στο general case οφείλουμε IMHO να θεωρήσουμε πως δεν μεριμνεί. Οπότε, αν όντως δεν μεριμνεί, τότε ούτε ο κώδικας του πάπι ούτε ο demi-κώδικας του defacer λύνουν το πρόβλημα του ts. Το ίδιο ακριβώς θέμα πρωτο-έθιξε ο timon, όταν ρώτησε τον ts αν ξέρει ή όχι το len, προφανώς αναφερόμενος στο BUF_DATALEN και όχι στο BUF_SIZE.
defacer Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 Λύσσα κακιά... int bytesToSend = 500; Πώς έπρεπε να την ονομάσω τη μεταβλητή για να καταλάβεις ότι δεν έχει καμία σχέση με το μήκος του buffer αλλά αντίθετα με το πόσα bytes επιθυμείς να στείλεις;
migf1 Δημοσ. 26 Μαΐου 2014 Δημοσ. 26 Μαΐου 2014 @imitheos: Ο κώδικας είναι του πάπι, δεν είναι δικός μου. Επίσης, δεν ισχυρίστηκα ποτέ πως είναι πιο readable από του defacer, ισχυρίστηκα και ισχυρίζομαι πως είναι overall καλύτερος από του defacer και μάλιστα εξήγησα τα γιατί (και τον χαρακτήρισα ιδανικό, γιατί αυτή είναι η άποψή μου). Σε ότι αφορά τα for και τα while, δεν έχω αντίρρηση (για μένα είναι το ίδιο readable για τη συγκεκριμένη περίπτωση που μιλάμε εδώ) αλλά επειδή δεν το έχω προσέξει αυτό που λες για τους οδηγούς (ή μπορεί να μην του έχω δώσει σημασία, η ουσία είναι πως δεν το θυμάμαι) θα μπορούσες να δώσεις links από 2-3 τέτοιους οδηγούς (υποθέτω μιλάς για coding-styles)? @defacer: Εγώ αυτό που ξέρω είναι αυτό που έγραψες. Εγώ από την άλλη μεριά, και διαχωρισμό έκανα στον κώδικα που έγραψα, και comment έβαλα, και ειδικό post αφιέρωσα (ξέρεις μωρέ, εκείνο το οποίο χαρακτήρισες "αχρείαστο" και κατόπιν έδωσες κώδικα με bytesToSend = 500, ίσο δηλαδή με το μήκος που ο ts είχε κάνει σαφές πως είναι το BUF_SIZE και είχε ξεκαθαρίσει πως στη γενική περίπτωση διαφέρει από το actual BUF_DATALEN. Λύσσα λες, ε; Κατά τα άλλα ήθελες και code review!
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα