Page 58 - Linux Inside τ. 10

Linux Inside
58
λά πρακτικά αυτή κάνει απλώς έναν ατέρμονο βρόχο, αντίστοιχο
του while(true). Αυτό όμως γίνεται στα παρασκήνια, οπότε και
πάλι ο χρήστης δεν χρειάζεται να μάθει περί βρόχων, κλήσεων
συναρτήσεων και ατέρμονων loops. Το μόνο που χρειάζεται να
κατανοήσει, είναι πως ό,τι θα γράψει στη setup() θα εκτελεστεί
μία φορά και στη συνέχεια θα εκτελείται συνεχόμενα ό,τι θα
γράψει στη loop(). Τέλος, θα παρατηρήσετε κάτι παράξενο. Είναι
η εντολή #line 1 που είναι αρκετά σπάνια για να την έχετε συνα-
ντήσει ξανά, όσο έμπειροι και αν είστε στη C. Αυτή λέει στον
preprocessor της C να αρχίσει το μέτρημα των γραμμών από
αυτό το σημείο, ξεκινώντας από τη γραμμή 1 και προχωρώντας.
Ο λόγος; Το αρχείο που θα δοθεί στο μεταγλωττιστή είναι μερι-
κές γραμμές μεγαλύτερο από το αρχικό μας και έτσι, αν έχουμε
ένα λάθος, π.χ., στη γραμμή 3 του προγράμματός μας, ο μετα-
γλωττιστής θα μας έλεγε ότι το λάθος είναι σε άλλη γραμμή,
π.χ., στη 13, γιατί το πρόγραμμα είναι διαφορετικό. Γι’ αυτόν το
λόγο λέμε στο μεταγλωττιστή να ξεκινήσει το μέτρημα των
γραμμών από εκεί που ξεκινάει ο κώδικάς μας, ώστε να μας δώ-
σει σωστό αριθμό γραμμής. Η δεύτερη σημαντική αλλαγή στη
σύνταξη του κώδικα έρχεται για να λύσει το θέμα των πρωτότυ-
πων συναρτήσεων. Θυμίζω ότι στις C και C++ δεν μπορείς να
χρησιμοποιήσεις μία συνάρτηση προτού την ορίσεις. Έτσι, δεδο-
μένου ότι έχουμε δύο συναρτήσεις που η μία ορίζει ή καλεί την
άλλη, ο παρακάτω κώδικας είναι σωστός:
int first()
{
//
do something
}
int second()
{
//
use the first
first();
//
do something else
}
Ο παρακάτω κώδικας όμως δεν είναι σωστός:
int first()
{
//
use the second
second();
//
do something
}
int second()
{
//
do something
Αυτό συμβαίνει επειδή στη δεύτερη περίπτωση ο μεταγλωτ-
τιστής δεν γνωρίζει ποια είναι η συνάρτηση second() που του
ζητήσαμε, αφού δεν την έχει διαβάσει ακόμα. Το πρόβλημα λύ-
νεται με τα πρωτότυπα συναρτήσεων (function prototypes). Το
πρωτότυπο μίας συνάρτησης, όπως δηλώνει και το όνομά του,
ορίζει ότι υπάρχει μία συνάρτηση με το συγκεκριμένο όνομα
και τη συγκεκριμένη συμπεριφορά (αριθμός και τύπος ορισμά-
των, τύπος δεδομένων που επιστρέφει). Το παραπάνω παρά-
δειγμα θα δουλέψει σωστά ως εξής:
int first(); //prototipo sinartisis
int second(); //prototipo sinartisis
int first()
{
//
use the second
second();
//
do something
}
int second()
{
//
do something
}
Θα παρατηρήσατε ότι προσθέσαμε και το πρωτότυπο της
πρώτης συνάρτησης, παρ’ όλο που δεν χρειάζεται στο παρά-
δειγμά μας. Σε γενικές γραμμές, είναι καλή πρακτική να ορί-
ζουμε τα πρωτότυπα των συναρτήσεων μας στην αρχή του κώ-
δικά μας. Όπως είπαμε προηγουμένως, στη γλώσσα του
Arduino έχει απλουστευθεί και αυτό το πρόβλημα. Συγκεκριμέ-
να, όταν το Arduino IDE δημιουργεί το C++ κώδικα από τον
κώδικά μας, ψάχνει για ορισμούς συναρτήσεων στον κώδικά
μας και δημιουργεί τα αντίστοιχα πρωτότυπα συναρτήσεων
στην αρχή. Έτσι, θεωρούμε ότι έχουμε τον παρακάτω κώδικα:
void setup() {
int first();
}
void loop(){
int second();
}
int first()
{
//
do something
}
int second()
{
//
do something else
}
Το πρόβλημα με τον παρακάτω κώδικα έγκειται στο ότι η
setup() καλεί τη first() και η loop() τη second() προτού αυτές
οριστούν. Ας δούμε το C++ κώδικα που θα παραχθεί από το
Arduino IDE και θα σταλεί στο μεταγλωτιστή.
#
include<Arduino.h>
int main(void)
{
setup();
for(;;)
loop();
}
int first();
int second();
#
line 1 "build/blink.ino"
void setup() {
int first();
}
void loop(){
int second();
}
int first()
{
//
do something
}
int second()
{
//
do something else
}
Βλέπουμε ότι το Arduino IDE έχει δημιουργήσει δύο πρωτό-
τυπα συναρτήσεων για τις συναρτήσεις που ορίσαμε εμείς για
να μας διευκολύνει και να μην μπερδεύει τους αρχάριους χρή-
στες χωρίς λόγο.
Project - Arduino Hacks