Skip to content

18. Θέματα στυλ στη C

Σύνοψη O ελεύθερος τρόπος γραφής προγραμμάτων στη C και τα προβλήματα που δημιουργεί, κανόνες στυλ, το clang-format για εύκολη μορφοποίηση κώδικα C, άλλα εργαλεία μορφοποίησης και ωραιοποίησης κώδικα, ιδιωματικός κώδικας στη C.

Προαπαιτούμενη γνώση Τύποι δεδομένων, είσοδος/έξοδος, δομές επιλογής και επανάληψης, συναρτήσεις, πίνακες, δείκτες, αλφαριθμητικά, διαμερισμός κώδικα, ορίσματα γραμμής εντολών.

18.1 Εισαγωγή

Η C δίνει τη δυνατότητα στους προγραμματιστές να γράφουν με οποιαδήποτε μορφή τον κώδικά τους, αρκεί να μην παραβιάζονται οι συντακτικοί κανόνες της γλώσσας. Αυτό δίνει μεγάλη ελευθερία στη μορφή που μπορεί να έχει ο κώδικας. Έτσι κώδικας όπως ο ακόλουθος είναι έγκυρος.

int*d,D[9999],N=20,L=4,n,m,k,a[3],i;char*p,*q,S[2000]="L@X‐SGD‐HNBBB‐AD‐VHSG‐\
‐XNT\x1b[2J\x1b[H",*s=S,*G="r2zZX!.+@KBK^yh.!:%Bud!.+Jyh.!6.BHBhp!6.BHBh!:%Bu\
v{VT!.hBJ6p!042ljn!284b}`!.hR6Dp!.hp!h.T6p!h.p6!2/LilqP72!h.+@QB!~}lqP72/Lil!\
h.+@QBFp!:)0?F]nwf!,82v!.sv{6!.l6!,j<n8!.xN6t!&NvN*!.6hp";/*Stay_on_target.**/
#include/**/<complex.h>/**//*Oh,my_dear_friend.How_I've_missed_you.‐‐C‐3PO***/
typedef/**/complex/**/double(c);c(X)[3],P,O;c/**/B(double t){double s=1‐t,u;P=
s*s*X[1]            +2        *s*t*        *X+t        *t*X       [2]+O;u=I*P;
return+48*((    s=P)+   48*I   )/(   1<u?   u:   1);}   /*   1977  IOCCC2020*/
#include/**    Do.Or   do_not   .   There_is_   no_try...   ‐‐Yoda**/<stdio.h>
void/**/b(    double   t,/***   *   **/double   u){double   s=P=B(t)‐B(u);(s=P
*(2*s‐P))    <1?m=P=B   ((t+   u)/   2),k   =‐   I*P,   m>   ‐41&&m<39&&9<k&&k
<48?               m+=k/      2*80+        73,S        [m]=               S[m]
‐73?k%2?S[m]‐94?95:73:S[m]‐95?94:73:73:1:(b(t,(t+u)/2),b((t+u)/2,u),0);}/*<oo>
_No.             _I_am_            IOCCC           1977                   ***/
#include/*****    your   father..   ‐‐DarthVader   **/   <time.h>/****   ****/
int(main)(int    (x),   char**V){;   clock_t(c)=   /*   */clock();;;   for(d=D
;m<26;m++,s    ++)*s>   63?*d++=m%   7*          16‐7   *8,*d++=m/   7*25,*d++
=*s‐64:0;;    if(V[1])   {;;;FILE   *F   =fopen(V[+1],   "r");for   (d=D,L=N=m
=0;(x=/**             *            ***              **/            fgetc(F))>0
||fclose(F);)if(x>13?64<x&&x<91?*d++=m*16,*d++=L*25,*d++=x%26:0,m++,0:1)for(++
L;d‐D>N*3||(m=0);N++)D[N*3]‐=m*8;}for(;i<200+L*25;i++){for(n=0,p=S+33;n<1920;*
p++=n++%80>78?10:32){}for(*p=x=0,d=D;x<N;x++,d+=3){O=(d[1]‐i‐40)*I+*d;n=d[2];p
=G;for(;n‐‐;)for(;*p++>33;);*a=a[1]=*p++;for(;*p>33;p++)if(*p%2?*a=*p,0:1){a[2
]=*p;for(m=0;m<3;m++){k=a[m]/2‐18;q="/&&&##%%##.+),A$$$$ '&&'&&((%‐((#'/#%%#&#\
&&#D&";for(n=2;k‐‐;)n+=*q++‐34;X[m]=n%13+n/13*I;}b(0,1);*a=a[1]=*p;}}for(puts(
s),s=S+30;(clock()‐c)*10<i*CLOCKS_PER_SEC;);}return 0;}/*Nevertellmetheodds*/

Κώδικας από τον 27ο διεθνή διαγωνισμό obfuscated C code (1).

  1. https://www.ioccc.org/2020/endoh2/index.html

Ένα κοινό στυλ γραφής προγραμμάτων καθιστά ευκολότερη τη συνεργασία πολλών προγραμματιστών στην από κοινού ανάπτυξη ενός λογισμικού. Έτσι θέματα όπως το εάν τοποθετούνται κενά πριν και μετά τους δυαδικούς τελεστές, πού τοποθετείται το * στη δήλωση δεικτών (κολλητά στον τύπο ή κολλητά στη μεταβλητή), αν χρησιμοποιούνται στηλοθέτες ή κενά (tabs or spaces), πού τοποθετείται η αγκύλη που ορίζει την αρχή της επανάληψης (στην ίδια γραμμή με την εντολή επανάληψης ή στην αμέσως επόμενη), μπορούν να αποτελέσουν πηγή διαφωνιών και προβλημάτων.
Γενικότερα, η υιοθέτηση κανόνων διευκολύνει την αναγνωσιμότητα και τη συντήρηση του κώδικα. Υπάρχουν λογισμικά όπως το clang-format που επιτρέπουν την αυτόματη μορφοποίηση του κώδικα σύμφωνα με στυλιστικές αποφάσεις που μπορούν να παραμετροποιηθούν. Πριν αναφερθούμε στο clang-format θα παρουσιαστούν ορισμένοι απλοί κανόνες στυλ.

18.2 Απλοί κανόνες στυλ

Η υιοθέτηση ενός καλού προγραμματιστικού στυλ μειώνει τα λάθη και ενισχύει την ανάπτυξη συνεπούς μορφής κώδικα που διαβάζεται εύκολα. Υπάρχουν πολλές πηγές που περιγράφουν τρόπους για να συμβεί αυτό όπως οι 1, 2 και 3.

Στη συνέχεια θα παρατεθούν ορισμένοι κανόνες που σχετίζονται με το καλό προγραμματιστικό στυλ.

  1. Διατήρηση με συνέπεια του ίδιου στυλ εσοχών, τοποθέτησης αγκυλών και χρήσης κενών σε όλο τον κώδικα. Για παράδειγμα υπάρχουν τα στυλ GNU, K&R, 1TBS (One True Base Style) και άλλα. Ακολουθούν παραδείγματα μορφοποίησης ενός κώδικα με τα τρία στυλ που αναφέρθηκαν:

    int main (void)
    {
        ...
        while (x == y)
        {
            do_something1 ();
            if (a_condition)
            {
                do_something2 ();
            }
            else
            {
                do_something3 ();
            }
        }
        do_something4 ();
        ...
    }
    
    int main(void)
    {
        ...
        while (x == y) {
            do_something1();
            if (a_condition)
                do_something2();
            else
                do_something3();
        }
        do_something4();
        ...
    }
    
    int main(void) {
        ...
        while (x == y) {
            do_something1();
            if (a_condition) {
                do_something2();
            } else {
                do_something3();
            }
        }
        do_something4();
        ...
    }  
    

    Παρατηρήστε ότι στο στυλ K&R, αν ένα μπλοκ κώδικα έχει μια μόνο εντολή, δεν χρησιμοποιούνται αγκύλες για να το περικλείουν.

  2. Χρήση επαρκώς περιγραφικών ονομάτων (π.χ. μεταβλητών, σταθερών, συναρτήσεων) που συνεισφέρουν στην εύκολη κατανόηση του κώδικα. Τα ονόματα θα πρέπει να αποδίδουν τον ρόλο της οντότητας που αναπαριστούν. Ονόματα συντομογραφίες ή μακροσκελή ονόματα συνήθως δεν είναι καλές επιλογές, ενώ το μήκος των ονομάτων θα πρέπει να είναι ανάλογο της εμβέλειάς τους. Έτσι, είναι αποδεκτό ως όνομα μεταβλητής για παράδειγμα το i αν πρόκειται για τη μεταβλητή επανάληψης μιας εντολής for.

  3. Συγγραφή ονομάτων με ένα στυλ. Τα δύο κύρια στυλ συγγραφής ονομάτων είναι το snake_case και το PascalCase. Για παράδειγμα, μια μεταβλητή για το πλήθος των κερδισμένων παιχνιδιών ενός παίκτη μπορεί να ονομαστεί ακολουθώντας το πρώτο στυλ ως player_games_won, ενώ ακολουθώντας το δεύτερο στυλ μπορεί να ονομαστεί ως PlayerGamesWon.

  4. Χρήση σχολίων στον κώδικα που να βοηθούν ουσιαστικά στην κατανόηση του κώδικα. Τα σχόλια πρέπει να μην είναι περιγράφουν κάτι που είναι προφανές, να είναι κατανοητά, να είναι ενημερωμένα και σε καμία περίπτωση να μη βρίσκονται σε αντίφαση με τον κώδικα. Για παράδειγμα, συνηθίζεται να τοποθετείται πάνω από συναρτήσεις ένα σχόλιο πολλών γραμμών που να επεξηγεί τη λειτουργία της συνάρτησης. Ο κώδικας 18.1 περιέχει ένα παράδειγμα αυτής της μορφής σχολίου.

    Κώδικας 18.1: ch18_p1.c - σχόλιο πολλών γραμμών με την περιγραφή της λειτουργικότητας, των εισόδων και των εξόδων μιας συνάρτησης.
    #include <stdio.h>
    
    /*
     * Function: scale_smallest_by_factor
     * ----------------------------------------------------------------------------
     *   Επιστρέφει τη μικρότερη τιμή από τις δύο πρώτες τιμές εισόδου
     *   πολλαπλασιασμένη με την τρίτη τιμή εισόδου
     *
     *   r1: ο πρώτος πραγματικός αριθμός
     *   r2: ο δεύτερος πραγματικός αριθμός
     *   f: ο συντελεστής πολλαπλασιασμού
     *
     *   returns: η μικρότερη τιμή από τα r1 και r2 πολλαπλασιασμένη με το f
     */
    double scale_smallest_by_factor(double r1, double r2, double f) {
      double min = r1;
      if (r2 < min) {
        min = r2;
      }
      return f * min;
    }
    
    int main(void) {
      double r = scale_smallest_by_factor(5.0, 4.0, 1.5);
      printf("Result %.2f\n", r);
      return 0;
    }
    

  5. Κάθε συνάρτηση πρέπει να εκτελεί μια λειτουργία και να είναι μικρού μεγέθους.

18.3 clang-format

Το clang-format (https://clang.llvm.org/docs/ClangFormat.html) είναι ένα λογισμικό μορφοποίησης κώδικα που επιτρέπει την εφαρμογή καθιερωμένων προγραμματιστικών στυλ κατά την ανάπτυξη κώδικα. Προγραμματιστές που αποτελούν μέλη μιας ομάδας ανάπτυξης λογισμικού μπορούν να επωφεληθούν από το clang-format έτσι ώστε ο κώδικας που αναπτύσσουν να έχει κοινό στυλ. Οι επιμέρους ρυθμίσεις του αποθηκεύονται σε ένα αρχείο τύπου YAML (Yet Another Markup Language) με όνομα .clang‐format ενώ IDEs όπως το VSCode χρησιμοποιούν αυτές τις ρυθμίσεις και πραγματοποιούν αυτόματες μορφοποιήσεις.
To clang-format είναι τμήμα του LLVM project και υποστηρίζει τη μορφοποίηση κώδικα που γράφεται και σε άλλες γλώσσες προγραμματισμού, πέρα από τη C, όπως η C++, Java, JavaScript, JSON, Objective-C, Protobuf και C#.

Εγκατάσταση του Clang-Format Η εγκατάσταση του clang-format γίνεται ως εξής:

  • Windows, υποθέτοντας ότι έχει ήδη εγκατασταθεί το λογισμικό διαχείρισης πακέτων λογισμικού chocolatey (1): choco install llvm

    1. https://chocolatey.org/
  • Windows WSL (Ubuntu): sudo apt install clang‐format

  • Linux Ubuntu: sudo apt install clang‐format
  • MacOS: brew install clang‐format

Ο έλεγχος της ορθής εγκατάστασης γίνεται πληκτρολογώντας clang‐format ‐‐version στη γραμμή εντολών, οπότε και θα πρέπει να επιστραφεί η έκδοση του clang-format (π.χ. clang-format version 16.0.5).

Προκαθορισμένα στυλ κώδικα στη C Υπάρχουν προκαθορισμένα στυλ που μπορούν να χρησιμοποιηθούν με το clang-format. Τα στυλ αυτά έχουν δημιουργηθεί και συνεχίζουν να αναπτύσσονται από εταιρείες ή οργανισμούς. Τα στυλ που υποστηρίζει το clang-format είναι τα: LLVM, GNU, Google, Chromium, Microsoft, Mozilla και Webkit.

Η κλήση του clang-format από τη γραμμή εντολών γίνεται προσδιορίζοντας με τον διακόπτη ‐‐style το όνομα του προκαθορισμένου στυλ. Για παράδειγμα η ακόλουθη κλήση του clang-format θα μετατρέψει το test.c σύμφωνα με το στυλ llvm:

$ clang‐format ‐style=llvm test.c

Αν οι αλλαγές δεν επιθυμούμε να επηρεάσουν το αρχείο test.c τότε η εντολή δέχεται επιπλέον τον διακόπτη ‐‐dry‐run. Περισσότερες πληροφορίες για τους διακόπτες του clang-format εμφανίζονται καλώντας το με τον διακόπτη ‐‐help
Ωστόσο, η συνηθισμένη πρακτική είναι να δημιουργηθεί ένα αρχείο .clang‐format χρησιμοποιώντας ως βάση ένα από τα προκαθορισμένα στυλ και στη συνέχεια να γίνουν τυχόν αλλαγές σε αυτό έτσι ώστε να ταιριάζει στις προτιμήσεις της ομάδας προγραμματιστών (ή του προγραμματιστή) που θα το χρησιμοποιήσουν. Η εντολή δημιουργίας του .clang‐format είναι η ακόλουθη (π.χ. για το στυλ llvm).

$ clang‐format ‐‐style=llvm ‐dump‐config > .clang‐format

To .clang‐format αρχείο αποτελείται από ρυθμίσεις της μορφής κλειδί: τιμή σύμφωνα με το πρότυπο αρχείων YAML. Ένα απόσπασμα του αρχείου .clang‐format, από τις πάνω από 200 γραμμές, που δημιουργήθηκαν με την παραπάνω εντολή φαίνεται στη συνέχεια:

‐‐‐
Language:           Cpp
# BasedOnStyle:     LLVM
...
ColumnLimit:        80
...
IndentWidth:        2
...
PointerAlignment:    Right
...
SpaceBeforeAssignmentOperators: true
...
TabWidth:           8
UseTab:             Never
...

Το αρχείο αποτελείται από πολλές ρυθμίσεις. Ανάμεσα σε άλλες ρυθμίσεις ορίζεται ότι το μέγιστο μήκος κάθε γραμμής θα είναι 80 χαρακτήρες, η εσοχή θα είναι 2 χαρακτήρες, οι δηλώσεις δεικτών θα στοιχίζουν το * δεξιά (π.χ. int *p; και όχι για παράδειγμα int* p;), θα υπάρχει κενό αριστερά και δεξιά από τον τελεστή ανάθεσης =, το πλάτος κάθε στηλοθέτη θα είναι 8 χαρακτήρες και άλλα.

Διάφορα IDEs επιτρέπουν την αυτόματη εφαρμογή των κανόνων στυλ που περιέχει το .clang‐format με κάποιον συνδυασμό πλήκτρων. Στο VSCode, η επέκταση xaverh/vscode‐clang‐format‐provider, εφόσον εγκατασταθεί, ορίζει το συνδυασμό πλήκτρων Alt+Shift+F (ταυτόχρονη πίεση των πλήκτρων Alt, Shift και F) για την εφαρμογή αυτόματης μορφοποίησης. Επίσης, στις ρυθμίσεις (settings) μπορεί να ενεργοποιηθεί η επιλογή “Editor: Format On Save”, που σημαίνει ότι όταν θα αποθηκεύεται ένα αρχείο, αυτόματα θα εφαρμόζεται μορφοποίηση με το clang-format. Η πρόσβαση στις ρυθμίσεις του VSCode γίνεται με τον συνδυασμό πλήκτρων Ctrl+, (ταυτόχρονη πίεση των πλήκτρων Control και κόμμα). Αντίστοιχα, μπορεί να αυτοματοποιηθεί η κλήση του clang-format για vim, emacs, CLion, Visual Studio κ.λπ.
Αν δεν είναι επιθυμητό να πραγματοποιηθεί εφαρμογή στυλ σε κάποιο τμήμα κώδικα, τότε μπορεί πριν και μετά το τμήμα αυτό να τοποθετηθούν ως σχόλια τα κείμενα clang‐format off και clang‐format οn αντίστοιχα. Ο κώδικας 18.2 είναι ένα σχετικό παράδειγμα.

Κώδικας 18.2: ch18_p2.c - απενεργοποίηση μορφοποίησης με το clang-format, σε τμήμα του κώδικα.
#include <stdio.h>

int main(void) {
  // clang-format off
         int a=    42;
    printf("a=%d\n", a);
  // clang-format on
  int b = 73;
  printf("b=%d\n", b);
  return 0;
}

Περισσότερες πληροφορίες για την εφαρμογή στυλ με το clang-format μπορούν να εντοπιστούν στο 4.

18.4 Άλλα λογισμικά εφαρμογής στυλ σε κώδικα C

Πέρα από το clang-format υπάρχουν και άλλα λογισμικά που μπορούν να χρησιμοποιηθούν για την εφαρμογή κανόνων στυλ σε κώδικα. Ορισμένα από αυτά είναι το GNU Indent, το Uncrustify, το Artistic Style και το clang-tidy.

Το GNU Indent (https://www.gnu.org/software/indent/) είναι ένα εργαλείο του GNU Project και μπορεί να κληθεί από τη γραμμή εντολών (με την εντολή gindent), έτσι ώστε να μορφοποιεί αυτόματα κώδικα τοποθετώντας κατάλληλες εσοχές σύμφωνα με τις οδηγίες στυλ κώδικα του GNU. Υποστηρίζει, όπως και το clang-format, τη ρύθμιση πολλών παραμέτρων και μπορεί να συνδυαστεί με άλλα εργαλεία ανάπτυξης προγραμμάτων.

Το Uncrustify είναι σύμφωνα με την περιγραφή του που υπάρχει στη σελίδα https://github.com/uncrustify/uncrustify, ένα εργαλείο ωραιοποίησης (beautifier) κώδικα. Χρησιμοποιεί ένα αρχείο ρυθμίσεων και μέσα σε αυτό καθορίζονται οι επιλογές μορφοποίησης που εφαρμόζει. Υποστηρίζει και άλλες γλώσσες επιπλέον της C όπως η C++, η C#, η Objective‐C και η Java.

To Artistic Style (https://astyle.sourceforge.net/) μορφοποιεί κώδικα σε C, C++, Objective‐C, C# και Java ακολουθώντας κανόνες για εσοχές, κενά κ.λπ. Μπορεί να κληθεί από τη γραμμή εντολών, ορίζοντας ρυθμίσεις μορφοποίησης με διακόπτες ή μπορεί να χρησιμοποιεί αρχείο ρυθμίσεων.

To Clang-Tidy όπως αναφέρθηκε στο Κεφάλαιο 16 είναι ένα λογισμικό στατικής ανάλυσης κώδικα. Ωστόσο, στην κατηγορία ελέγχων αναγνωσιμότητα (readability) περιέχει ελέγχους που σχετίζονται με τη μορφή του κώδικα έτσι ώστε να επιτυγχάνεται καλύτερη αναγνωσιμότητα του κώδικα.

18.5 Ιδιώματα C

Τα ιδιώματα C (C idioms) είναι αποσπάσματα κώδικα που ακολουθούν κοινά αποδεκτές συμβάσεις, πρακτικές και οδηγίες στυλ για τη γλώσσα C. Αποτελούν προτεινόμενο και φυσικό τρόπο για να γράφει κανείς κώδικα C ακολουθώντας βέλτιστες πρακτικές. Η έμφαση δίνεται στην αποδοτικότητα και στην αναγνωσιμότητα με συνοπτικό τρόπο. Τα ιδιώματα C έχουν δημιουργηθεί από την κοινότητα των προγραμματιστών C. Η γενική αντίληψη για τα ιδιώματα είναι ότι αξίζει κανείς να τα χρησιμοποιεί για να λύνει τα προβλήματα που επιλύουν, έναντι εναλλακτικών τρόπων.
Η χρήση των ιδιωμάτων της C υποδηλώνει υψηλή γνώση της γλώσσας, ικανότητα χρήσης των δυνατοτήτων της και κατανόηση καλών πρακτικών. Επιτρέπει σε άλλους προγραμματιστές της C να καταλάβουν γρήγορα τον σκοπό ενός κώδικα, προωθεί την επαναχρησιμοποίηση του κώδικα και διευκολύνει τη συνεργασία και τη διατήρηση κοινών αποθετηρίων κώδικα.

Στη συνέχεια ακολουθούν μερικά παραδείγματα ιδιωμάτων της C.

  1. Αρχικοποίηση ενός αλφαριθμητικού. Η ανάθεση αρχικής τιμής σε ένα αλφαριθμητικό όπως στη συνέχεια, υποδηλώνει ότι δεν επιτρέπεται η αλλαγή του αλφαριθμητικού:

    const char *message = "Keep Calm!";
    
    Η χρήση του const απαγορεύει την αλλαγή του περιεχομένου της μεταβλητής message.

  2. Αλφαριθμητικά πολλαπλών γραμμών. Η ενσωμάτωση ενός μεγάλου αλφαριθμητικού στον κώδικα είναι προτιμότερο να γίνεται με το χαρακτηριστικό της αυτόματης συνένωσης διαδοχικών αλφαριθμητικών της C. Για παράδειγμα η ακόλουθη εντολή εμφανίζει ένα κείμενο σε μια γραμμή.

    printf("C is a razor‐sharp tool, with which "
               "one can create an elegant and efficient program "
               "or a bloody mess. "
               " Brian Kernighan")
    

  3. Σύγκριση αν δύο αλφαριθμητικά είναι ίσα.

    if (!strcmp(s1, s2)) {
    ... // τα λεκτικά s1 και s2 είναι ίσα
    }
    
    Θα πρέπει να γίνει include το string.h. Ο κώδικας εκμεταλλεύεται την τιμή επιστροφής 0 της strcmp() στην περίπτωση που τα ορίσματά της είναι ίσα αλφαριθμητικά.

  4. Εμφάνιση πίνακα αλφαριθμητικών με κόμματα μεταξύ των στοιχείων του πίνακα. Ο κώδικας 18.3 είναι ένα σχετικό παράδειγμα.

    Κώδικας 18.3: ch18_p3.c - εμφάνιση στοιχείων πίνακα αλφαριθμητικών, διαχωρισμένων μεταξύ τους με κόμματα.
    #include <stdio.h>
    #define N 3
    int main(void) {
      char *items[N] = {"Dennis Ritchie", "Ken Thompson", "Brian Kernighan"};
      const char *prefix = "";
      for (int i = 0; i < N; i++) {
        printf("%s%s", prefix, items[i]);
        prefix = ", ";
      }
      return 0;
    }
    
    Η εκτέλεση του κώδικα θα εμφανίσει τα ακόλουθα αποτελέσματα:
    Dennis Ritchie , Ken Thompson , Brian Kernighan
    

  5. Εμφάνιση του τελευταίου στοιχείου ενός πίνακα. Στον κώδικα 18.4 παρουσιάζεται ένα παράδειγμα εμφάνισης του τελευταίου στοιχείου ενός πίνακα ακεραίων.

    Κώδικας 18.4: ch18_p4.c - απευθείας μετάβαση στο τελευταίο στοιχείο ενός πίνακα.
    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
    
    int main(void) {
      int items[] = {5, 16, 7, 21, 32};
      int length = sizeof(items) / sizeof(items[0]);
      printf("%d\n", items[length - 1]);
      return 0;
    }
    

  6. Διάσχιση των στοιχείων ενός πίνακα. Ο κώδικας 18.5 διασχίζει έναν πίνακα ακεραίων και εμφανίζει τα στοιχεία του.

    Κώδικας 18.5: ch18_p5.c - εμφάνιση των στοιχείων ενός πίνακα, χωρίς να χρησιμοποιείται ρητά η τιμή του μεγέθους του πίνακα
    #include <stdio.h>
    
    int main(void) {
      int items[] = {8, 17, 9, 42, 73, 21};
      for (size_t i = 0; i < sizeof(items) / sizeof(items[0]); i++) {
        printf("%d\t", items[i]);
      }
      printf("\n");
      return 0;
    }
    
    Η εκτέλεση του προγράμματος θα εμφανίσει:
    8   17  9   42  73  21
    

  7. Aνάγνωση χαρακτήρα προς χαρακτήρα της εισόδου μέχρι να εισαχθεί η ειδική τιμή EOF. Ο κώδικας 18.6 διαβάζει έναν χαρακτήρα τη φορά και τερματίζει όταν πληκτρολογηθεί Ctrl+D σε Linux και MacOS ή Ctrl+Z στα Windows, που είναι ο τρόπος εισόδου της ειδικής τιμής EOF.

    Κώδικας 18.6: ch18_p6.c - είσοδος χαρακτήρων από τον χρήστη και τερματισμός μόλις εισαχθεί η ειδική τιμή EOF.
    #include <stdio.h>
    
    int main(void) {
      int ch;
      while ((ch = getchar()) != EOF) {
        printf("%c", ch);
      }
      printf("Input ended\n"); // Ctrl+D για EOF στο Linux - MacOS
                               // Ctrl+Z για EOF στα Windows
      return 0;
    }
    
    Ένα παράδειγμα εκτέλεσης του κώδικα είναι το ακόλουθο:
    abc             <‐‐ είσοδος χαρακτήρων από τον χρήστη και enter
    abc             <‐‐ έξοδος
    def             <‐‐ είσοδος χαρακτήρων από τον χρήστη και enter
    def             <‐‐ έξοδος
                    <‐‐ εισαγωγή Ctrl+Z (σε Windows) από τον χρήστη
    Input ended     <‐‐ μήνυμα πριν τον τερματισμό
    

Μια πηγή εντοπισμού ιδιωματικού κώδικα για τη C αλλά και για διάφορες άλλες γλώσσες προγραμματισμού είναι το https://programming‐idioms.org/.

18.6 Ασκήσεις

Άσκηση 1
Γράψτε μια συνάρτηση που να δέχεται ως ορίσματα δύο πραγματικούς αριθμούς a και b και να επιστρέφει έναν τυχαίο πραγματικό αριθμό επιλεγμένο ομοιόμορφα από το διάστημα τιμών [a,b). Καλέστε τη συνάρτηση από το κύριο πρόγραμμα. Μορφοποιήστε το πρόγραμμα χρησιμοποιώντας τις οδηγίες στυλ GNU με το clang-format.

Άσκηση 2
Εντοπίστε όλες τις πιθανές επιλογές στυλ που υποστηρίζει το clang-format καλώντας το clang-format από τη γραμμή εντολών με τον διακόπτη ‐‐help. Μορφοποιήστε έναν κώδικα, με τρεις εμφωλευμένες επαναλήψεις, που να εντοπίζει όλες τις ακέραιες λύσεις της εξίσωσης 12𝑥−14𝑦+81𝑧 = 100 για ακέραιες τιμές των 𝑥, 𝑦 και 𝑧 στο διάστημα [1, 100], χρησιμοποιώντας όλα τα διαθέσιμα στυλ του clang-format.
Ποιο ή ποια στυλ δίνουν τον κώδικα με το μικρότερο πλήθος γραμμών;

Άσκηση 3
Δίνεται ο κώδικας 18.7 που εμφανίζει όλους τους ακέραιους αριθμούς από μια ακέραια τιμή i1μέχρι μια άλλη ακέραια τιμή i2, θεωρώντας ότι οι δύο αυτές τιμές δίνονται ως ορίσματα γραμμής εντολών. Συμπιέστε όσο μπορείτε τον κώδικα από τη γραμμή 10 μέχρι τη γραμμή 33 έτσι ώστε να χρησιμοποιεί τους λιγότερους δυνατούς χαρακτήρες και να διατηρεί την ίδια λειτουργικότητα. Στη συνέχεια, δείτε τις λύσεις που προτάθηκαν για αυτό το πρόβλημα στον διαγωνισμό ShoCC (https://www.unix‐ag.uni‐kl.de/~conrad/shocc/results.html) το μακρινό 1995.

Κώδικας 18.7: ch18_e3.c - εκτύπωση όλων των ακέραιων αριθμών ανάμεσα σε δύο ακέραιους αριθμούς (συμπεριλαμβανομένων των τιμών αυτών) που δίνονται ως ορίσματα γραμμής εντολών.
/*
 * Κώδικας από το https://www.unix-ag.uni-kl.de/~conrad/shocc/example.c
 * με μικρές τροποποιήσεις
 */
#include <stdio.h>
#include <stdlib.h>

void o(int n) { printf("%d ", n); }

int main(int argc, char *argv[]) {
  int i1, i2, i, increment;

  if (argc != 3) {
    printf("Wrong number of arguments!\n");
    return -1;
  }

  i1 = atoi(argv[1]);
  i2 = atoi(argv[2]);

  if (i1 < i2) {
    increment = 1;
  } else {
    increment = -1;
  }

  for (i = i1; i != i2; i = i + increment) {
    o(i);
  }

  o(i2);
  return 0;
}

Ακολουθεί ένα παράδειγμα μεταγλώττισης και εκτέλεσης του κώδικα:

$ gcc ch18_e3.c ‐o ch18_e3
$ ./ch18_e3 9 5
9 8 7 6 5

Άσκηση 4
Μεταβείτε στο https://programming‐idioms.org/idiom/167/trim‐prefix. Χρησιμοποιώντας το ιδίωμα που περιγράφεται εκεί, τροποποιήστε τον κώδικα 18.8 έτσι ώστε να εκτυπώνει κάθε στοιχείο του πίνακα χωρίς το πρόθεμα Mr. ή Ms., εάν αυτό υπάρχει.

Κώδικας 18.8: ch18_e4.c - εκτύπωση ονομάτων που βρίσκονται σε έναν πίνακα, ζητείται τροποποίηση έτσι ώστε τα προθέματα Mr. και Ms. των ονομάτων να μην εμφανίζονται, εάν υπάρχουν.
#include <stdio.h>
#include <string.h>

int main(void) {
  char *names[] = {"Mr. Chris", "Ms. Ada",   "George",  "Mr. John",
                   "Anna",      "Ms. Sofia", "Mr. Alex"};
  for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
    printf("%s\n", names[i]);
  }
  return 0;
}

  1. Glenn Skinner, Suryakanta Shah και Bill Shannon. “C Style and Coding Standards”. Στο: Sun Internal Paper, Token 2151 (). 

  2. Jerry Doland και Jon Valett. C style guide. Αδημοσίευτη ερευνητική εργασία. Accessed: 2023-06-01.1994. 

  3. L.W. Cannon κ.ά. Recommended C Style and Coding Standards. http://dmst.aueb.gr/dds/res/cstyle/indexw.htm. Accessed: 2023-06-01. 

  4. CLANG-FORMAT STYLE OPTIONS. https://clang.llvm.org/docs/ClangFormatStyleOptions.html. Accessed: 2023-06-01.