Τετάρτη 12 Απριλίου 2017

Διάρθρωση Μνήμης Παραδείγματα.



Σε αυτήν την ανάρτηση δίνω ένα παράδειγμα σε δυο φάσεις. Σε πρώτη φάση φαίνεται πως γράφουμε και διαβάζουμε σε μια Διάρθρωση μνήμης και τι είναι η Δομή μνήμης. Ειδικότερα φαίνεται η χρήση της ένωσης (union) όπου ίδιο μέρος της δομής έχει δεύτερο (θα μπορούσε να είχε και τρίτο και άλλο ακόμα) σετ offsets, εδώ το offset είναι "η θέση από την αρχή" το οποίο μπορεί να το δει κανείς σε μια συνεχόμενη μνήμη ότι την μοιράζει σε μια έκταση πριν και μια μετά. Η έκταση πριν έχει ακριβώς την τιμή της θέσης αυτής. Ενώ η έκταση μετά είναι η διαφορά της θέσης από το σύνολο. Εδώ είναι καλό να αντιληφθεί κανείς ότι στην μνήμη δεν υπάρχουν "σημεία", έτσι το offset δεν το χρειαζόμαστε για να μας χωρίσει την μνήμη σε δυο μέρη, αλλά για να μας δείξει στη θέση που δηλώνει τι ακριβώς μπορούμε να πάρουμε ή να βάλουμε, Οπότε απαραίτητα στοιχεία για να ορίζουμε offset είναι δύο, η θέση από την αρχή και η έκταση του στοιχείου που ξεκινάει από αυτή τη θέση.

Βλέπουμε λοιπόν ότι στον ορισμό δομής (μνήμης) δίνουμε ονόματα και τύπο. Οι τύποι μπορεί να είναι οι απλοί Ψηφίο, Ακέραιος, Μακρύς, Διπλός, ή να είναι Δομές που φτιάχνουμε. Και τα πέντε έχουν μήκος σε Byte (ή Ψηφία), και οι απλοί έχουν 1,2,4,8 όπως τους διαβάζουμε. Η δομή βρίσκει άμεσα το μέγεθός της και το δίνει με την Μήκος().
Ας μετρήσουμε την Δομή δ1. Ξεκινάει με "κεντρική" θέση το 0 και βλέπουμε την εφαρμογή μιας ένωσης (ανοίγει μια αγκύλη) οπότε αποθηκεύει τη θέση πρόσκαιρα, και βλέπει τι έχει στις αγκύλες. Διαβάζει ένα όνομα, το θέσηψηφίου και βάζει το 0, ότι είναι ψηφίο (1byte) και αφήνει όσα byte του λέει το *16 και κάνει την θέση 16. Κλείνει όμως η αγκύλη και επαναφέρει την θέση στο 0. Διαβάζει το χπ και βάζει σε αυτό τη θέση 0 και την έκταση 8 (τόσο έχει ο διπλός, ο αριθμός κινητής υποδιαστολής διπλού μεγέθους από τον παλιό των 4 bit ή 5bit). Προσθέτει στη θέση 0 το 8 και τώρα με το 8 βρίσκει το ψπ, και πάλι εδώ θα βάλει στο ψπ θέση το 8, και μέγεθος το 8 και θα προσθέσει στο μετρητή της  "κεντρικής" θέσης που είναι στο 8 το 8 και θα γίνει 16. Εκεί τελειώνουν "οι θέσεις από την αρχή", τα offsets. Η δομή δ1 έχει μήκος 16 ψηφία (bytes) (ακριβώς όσο η κεντρική θέση). Οι δομές στη Μ2000 είναι Καταστάσεις, οι οποίες είναι μόνο για ανάγνωση. και τις χρησιμοποιούν οι Διαρθρώσεις Μνήμης, αλλά και εμείς αν μας ενδιαφέρει κάποια θέση από την αρχή. Όσο για την έκταση της κάθε θέσης, η Διάρθρωση ενημερώνεται, ενώ εμείς απλά διαβάζουμε τη δομή! Να ξεκαθαρίσω ότι η Δομή δεν δίνει άμεσα μνήμη, αυτό το κάνει η Διάρθρωση.

Μπορούμε με μια εντολή Γενική δ1πριν τον ορισμό της δομής να κάνουμε τη δομή μας να βρίσκεται παντού. Όμως δεν είναι απαραίτητο αν δεν θα φτιάξουμε αλλού Διαρθρώσεις. Εξάλλου μια Διάρθρωση κρατάει εσωτερικά δείκτη στη Δομή. Στην εντολή Γενική δεν δίνουμε τιμή στην δ1. Θα δώσουμε τη δομή μετά. Οι δομές είναι μόνο για ανάγνωση. 

Οι  Διαρθρώσεις (Buffers), δέχονται μια δομή, απλή ή σύνθετη και προαιρετικά ένα * με μια έκφραση ως προς τον αριθμό των στοιχείων. Μπορούμε με το Κενή, δηλαδή Διάρθρωση Κενή  να ετοιμάσουμε την μνήμη με μηδενισμό της. Μετά τον ορισμό της Διάρθρωσης μπορούμε να αλλάζουμε μόνο τον αριθό που πολλαπλασιάζει το μήκος της δομής (εν τέλει προσθέτει ή αφαιρεί μνήμη) , δηλαδή να έχουμε πίνακα δομών. Στην δομή δ1 το ένα μέρος της ένωσης είναι πίνακας ψηφίων με 16 στοιχεία (ψηφία). Η αλλαγή της μνήμης αν σημαίνει αύξηση, και δεν έχουμε ζητήσει καθαρό δεν θα σβήσει τα στοιχεία που υπάρχουν ήδη. 

Σκοπώς των διαρθρώσεων μνήμης είναι οι κλήσεις εξωτερικών συναρτήσεων με παροχή διευθύνσεων στην μνήμη. Η διάρθρωση μας δίνει φυσικές διευθύνσεις, με ή χωρίς προσθήκη "θέσης από την αρχή" και έχει τέσσερις τρόπους για να "πάρει αντίγραφο" από το χώρο της:
1. Χρήση της Εκφρ() με πρώτο στοιχείο τον δείκτη στην Διάρθρωση και δεύτερο το συνδυασμό αριθμού δομής (από 0) και offset (θέση από την αρχή) και φυσικά από το μήκος στοιχείου εντός της δομής. Η εγγραφή γίνεται με την Επιστροφή.
2, Όπως το 1 αλλά ζητάμε από θέση ψηφίου, με χρήση οποιασδήποτε έκφρασης και με τύπο αυτό που ορίζουε άμεσα.
3. Εγγραφή/Ανάγνωση Utf-16 Αλφαριθμητικό. Χρήση της Εκφρ$(), με παράμετρο μόνο το δείκτη της Διάρθρωσης θα δώσει όλη τη μνήμη σαν ένα αλφαριθμητικό. Με ένα χαρακτήρα θα δώσει το μέγεθος που θέλουμε, με δύο θα δώσουμε μαζί με το δείκτη, την αρχή και το δεύτερο το μήκος που θα μας επιστρέψει.
4. Εγγραφή/Ανάγνωση ANSI Όπως το προηγούμενο αλλά τώρα οι χαρακτήρες πιάνουν μόνο ένα ψηφίο (byte).

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

Σε προηγούμενο παράδειγμα prime numbers - Using in C βάζω στη διάρθρωση 10 εκατομμύρια long (Μακρύς), 40 Mbyte το δίνω σε συνάρτηση C και μου επιστρέφει, αποτέλεσμα στα 2.5 Mbyte, πάνω από 600.000 πρώτους, σε λιγότερο από μισό δευτερόλεπτο, και απ' ευθείας τα γράφω σε αρχείο, και κατόπιν δείχνω πως τα εισάγω, και εμφανίζω τους >600k πρώτους στην οθόνη.


Εικόνα από Wine σε Linux. Οι μετατροπές γλώσσας είχαν επιτυχία! Έχω κάνει την Επιφάνεια (Desktop) με διαφάνεια στο 200 (255 χωρίς διαφάνεια, ενώ 0 είναι 100% διάφανο)







\\ 1. Δομή με χρήση ένωσης (union)
\\ διαβάζοντας ο διερμηνευτής την εσωτερική αγκύλη βάζει στην άκρη την τιμή της έκτασης ψηφίων στο σημείο αυτό
\\ και στην επιστροφή το ξαναπαίρνει, έτσι το θέσηψηφίου και το χπ έχουν την ίδια τιμή
\\ εκτός από τη θέση για κάθε όνομα γράφει και το τύπο,
\\ έτσι ξέρει ότι στην θέσηψηφίου!3 θα είναι η "έκταση" (offset) 3 γιατί έχει ψηφία (Bytes)


Δομή δ1 {
      {
            θέσηψηφίου ως ψηφίο*16
      }
      χπ ως διπλός
      ψπ ως διπλός
}
Διάρθρωση Κενή α ως δ1
Επιστροφή α, 0!χπ:=1.5, 0!ψπ:=30.12
Τύπωσε έκφραση(α, 0!χπ), έκφραση(α, 0!ψπ)
Επιστροφή α, 0!θέσηψηφίου!0:=-1.5 ως διπλός, 0!θέσηψηφίου!8:=-30.12 ως διπλός
Τύπωσε έκφραση(α, 0!χπ), έκφραση(α, 0!ψπ)


\\ Διάρθρωση ως πίνακας ψηφίων μόνο


Διάρθρωση Κενή β ως ψηφίο*Μήκος(δ1)
Επιστροφή β, 0:=-1.5 ως διπλός, 8:=-30.12 ως διπλός
Τύπωσε έκφραση(β, 0 ως διπλός), έκφραση(β, 8 ως διπλός)


\\ ο Μακρύς, όπως το ψηφίο (1 byte) και ο ακέραιος (2 byte) είναι  αριθμοί χωρίς πρόσημο
\\ ο ακέραιος στις δομές είναι δεν είναι ίδιος με τον ακέραιο σε μεταβλητή με % στο τέλος.
\\ ο ακέραιος σε μεταβλητή με % είναι εσωτερικά διπλός (double) χωρίς πρόσημο
\\ και έτσι χωράει ακέραιες τιμές χωρίς πρόσημο.


Δεκαεξ έκφραση(β, 0 ως Μακρύς), έκφραση(β, 4 ως Μακρύς), έκφραση(β,7) \\ εκτύπωση δεκαεξαδικών


\\ η Συνάρτηση Έκφρ() έχει πολλές παραλλαγές ανάλογα με το αντικείμενο, και στο όνομα υπάρχει και σαν Έκφραση()
\\ Μπορούμε να γράψουμε έναν ακέραιο με πρόσημο κάνοντας μετατροπή σε unsign για να διατηρεί τα bit
\\ εδώ πρέπει να ορίσουμε τι δίνουμε γιατί διαφορετικά ζητάει ψηφίo (byte) και θα βγάλει λάθος!


Επιστροφή β, 0:=Δυαδικό.Ακέραιο(-100) ως Ακέραιος
\\ δηλώνουμε ότι έχουμε δυο για μετατροπή από δυαδικό (χωρίς πρόσημο) σε ακέραιο (με πρόσημο)


Τύπωσε Ακέραιο.Δυαδικό(Εκφρ(β, 0 ως Ακέραιος),2) , Εκφρ(β, 0 ως Ακέραιος) , " 0x"+Δεκαεξ$(Εκφρ(β, 0 ως Ακέραιος),2)\\ δίνει -100 65436


\\ Μπορούμε να γράψουμε τον α στο β
\\ χρησιμοποιούμε το Έκφραση$() που για τις διαρθρώσεις εξάγει σε αλφαριθμητικό από το σημείο που θέλουμε και το μήκος που θέλουμε
\\ Ο διορθωτής ελέγχει αν μπορεί να πάρει αυτά που ζητάμε και αν όχι δίνει λάθος
\\ Ομοίως ελέγχει αν χωράνε να μπουν εκεί που τα βάζουμε


Επιστροφή β, 0:=Εκφραση$(α, 0,Μήκος(α))
Τύπωσε έκφραση(β, 0 ως διπλός), έκφραση(β, 8 ως διπλός)
Τύπωσε έκφραση(β, δ1("χπ") ως διπλός), έκφραση(β, δ1("ψπ") ως διπλός)
\\ Μπορούμε να αυξήσουμε το μήκος μιας διάρθρωσης χωρίς να πειράξουμε τα στοιχεία της
\\ δεν βάζουμε το αναγνωριστικό Κενή
\\ δεν μπορούμε να αλλάξουμε το τύπο στοιχείου - αλλά μπορούμε από την αρχή να έχουμε δομή με ένωση (union)
Διάρθρωση β ως ψηφίο*200
Επιστροφή β, 50:="όνομα"   \\ πιάνει 10 θέσεις ψηφίων
Τύπωσε Έκφρ$(β, 50, 5*2)


\\ 2. Εγγραφή στη διάρθρωση UTF-16LE και Ansi (8bit)
\\ Το παρακάτω είναι κομμάτι δύσκολο
\\ Πώς μπορούμε να αποθηκεύουμε ας πούμε ρώσικα με ένα byte χαρακτήρα;
\\
\\ μπορούμε να γράφουμε και να διαβάζουμε με  αλφαριθμητικά με ένα χαρακτήρα
\\ εδώ με χρήση γλώσσας - το 1049 για τα ρώσσικα
\\ φαίνεται πολύπλοκη η παρακάτω έκφραση αλλά γίνεται το εξής:
\\ η εσωτερική γραφή μετατρέπει τους κωδικούς από unicode ως 8bit ρώσικο μόνο ως προς τους κωδικούς
\\ παραμένει Unicode
\\ η χαρ$ μετατρέπει τους κωδικούς των γραμμάτων σε Unicode με τη γραμματοσειρά συστήματος
Τύπωσε Κωδ(γραφη$("П",1049)) ' δίνει το 73, η μετατροπή δεν πετυχαίνει
Τύπωσε Χαρκωδ(γραφη$("П",1049)) ' δίνει το 207, αυτό θέλουμε!
\\ αυτό που θέλουμε είναι να γυρνάει η Κωδ() ή Asc() το 207
Τύπωσε Κωδ(χαρ$(γραφη$("П",1049),0)) \\ πράγματι αυτό συμβαίνει με την Χαρ$(..., 0)
\\ η γραφή$ χωρίς δεύτερη παράμετρο κάνει το αλφαριθμητικό πραγματικό 8bit και φέρνει τους κωδικούς αντίστροφα από την προηγούμενη συνάρτηση (αλλά σε θέση του ενός byte ο χαρακτήρας).
Επιστροφή β, 70:= γραφη$(χαρ$(γραφη$("Привет игровая площадка!",1049),0))+χαρ$(0) \\ 25 χαρακτήρες
\\ Ας πάρουμε το πρώτο χαρακτήρα
Π=Εκφρ(β,70)
Τύπωσε Π, Κωδ("П"), Χαρκωδ("П") \\ θα δώσει το 207,  δίπλα το 63 που σημαίνει ? δεν αναγνωρίζεται και το 1055
Τύπωσε χαρ$(207,1049) \\ θα δώσει το "П" ρώσικο, γιατί έκανε την μετατροπή
\\ Η Έκφρ$(β, 70, 24) γυρνάει όμως Unicode και εδώ είναι μπερδεμένο γιατί σε ένα χαρακτήρα των 2 Byte
\\ έχουμε βάλει δυο χαρακτήρες του ενός
\\ Η χαρ$() χωρίς παράμετρο απλώνει τους χαρακτήρες με τον ίδιο κωδικό.
\\ Για τα ελληνικά και Αγγλικά δεν υπάρχει θέμα γίνεται αυτόματα!
Επιστροφή β, 50:= γραφη$("Γιώργος ABCDEF")
\\ το παραπάνω θα δουλέψει αν ισχύει αυτό: Κωδ("Γ")=195
\\ η συνάρτηση Κωδ("Γ") θα γυρίσει 63 αν το Γ δεν υποστηρίζεται από τους χαρακτήρες 8-bit του συστήματος.
\\ Η M2000 τρέχει σε υπολογιστή με οποιαδήποτε γλώσσα, γιατί χρησιμοποιεί εσωτερικά UTF-16LE, αλλά δεν μπορεί να αλλάξει τη γλώσσα του συστήματος.


\\ Το αποτέλεσμα:
Τύπωσε χαρ$(χαρ$(Έκφρ$(β, 70, 24)),1049)
\\ Στα ελληνικά απλά η χαρ$() κάνει τα 12 byte Ascii σε 24 byte Unicode
Τύπωσε χαρ$(Έκφρ$(β, 50, 12))
\\ Ασφαλώς με χρήση unicode είναι πιο εύκολα
Επιστροφή β, 120:= "Γιώργος ABCDEF Привет игровая площадка!"+χαρ$(0)
\\ Τα μηδενικά στο τέλος τα χρησιμοποιούμε αν θέλουμε το αλφαριθμητικό να το διαβάσει συνάρτηση της C
\\ Αν μας επιστρέψει τιμή τότε θα πρέπει να βρούμε το μήκος. Έχουμε όμως ορίσει το μέγιστο οπότε
\\ εδώ τραβάμε το τέλος και κόβουμε μέχρι το 0
Τύπωσε ΑριστερόΜέρος$(Έκφρ$(β, 120, 80), χαρ$(0)) 'επειδή έχουμε 200 byte όλο το β
\\ ενώ αν γνωρίζουμε το μήκος
Τύπωσε Έκφρ$(β, 120, 78) \\ θα το πάρουμε όλο!
\\ ή θα πάρουμε μέρος αυτού
Τύπωσε Έκφρ$(β, 150,48) \\ μπορούμε να βγάλουμε μέρος - εδώ υπολογίζουμε μήκος και έκταση σε bytes


Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.