pointer-to-object casting και ISO C++

Giorgos Keramidas keramida at ceid.upatras.gr
Wed Mar 1 14:37:55 EET 2006


On 2006-03-01 04:03, Eustathios Kamperis <ekamperi at auth.gr> wrote:
> Καλημέρα σε όλους!
>
> Θεωρήστε το εξής κομμάτι κώδικα:
>
> void foo(const void *pf) {
>   cout << "Function address: " << pf << endl;
> }
>
> void tralala() {
> }
>
> foo((void *) &tralala);

Αυτό το κομμάτι κώδικα δεν είναι κάτι που μπορεί να το κάνει compile
κάποιος.  Τυχαίνει να είναι αρκετό για να καταλάβω τι λες, αλλά σε
παρακαλώ αν θες βοήθεια με κάτι πιο περίπλοκο να στέλνεις κάτι που
μπορεί να γίνει compile, για να μπορούμε να το δοκιμάσουμε πιο εύκολα.

> Αν κάνω compile με την παράμετρο -pedantic, ο compiler παραπονείται
> για το εξής:
>
> "warning: ISO C++ forbids casting between pointer-to-function and
> pointer-to-object"
>
> Αν παραλείψω την παράμετρο -pedantic, το πρόγραμμα μεταγλωττίζεται και
> εκτελείται σωστά.

Πολύ σωστά.  Στο C standard λέει:

    6.3.2.3  Pointers

    [...]

    8 A pointer to a function of one type may be converted to a pointer
      to a function of another type and back again; the result shall
      compare equal to the original pointer. If a converted pointer is
      used to call a function whose type is not compatible with the
      pointed-to type, the behavior is undefined.

Οι pointers για functions και οι pointers για `objects' (στην οποία
κατηγορία ανήκουν και οι `void *' pointers) ανήκουν, πιθανόν, σε
διαφορετικά address spaces.  Το γεγονός ότι το standard ορίζει μόνο τη
μετατροπή από function pointer σε άλλο function pointer, σημαίνει ότι
δεν είναι καλά ορισμένη η μετατροπή σε `void *'.

> Γνωρίζετε κάποιο τρόπο *συνεπή* με το πρότυπο της C++ κατά ISO για να
> περνάω στη foo() τη διεύθυνση της tralala(). Αν όχι, έχετε να μου
> προτείνετε κάποια εναλλακτική προσέγγιση στο όλο θέμα;

Δεν υπάρχει τέτοιος τρόπος, από όσο ξέρω.  Το πρότυπο της C δεν είναι
ακριβώς «κανόνες τους οποίους κάποια στιγμή αποφάσισε η επιτροπή η οποία
το έγραψε να τους επιβάλλει με το έτσι θέλω».  Αντίθετα προσπαθεί να
αφήσει αρκετή ελευθερία στους implementors, για να μπορούν να συνεχίσουν
να χρησιμοποιούν μεγάλο μέρος από τα υπάρχοντα προγράμματα.

Αυτό σημαίνει πως σε ορισμένες περιπτώσεις, το «παρελθόν» που έχουν
κάποιες υλοποιήσεις (τόσο σε υλικό όσο και σε προγράμματα), μπορεί να
θεωρηθεί ότι ταιριάζει με το πρότυπο.

Ενα κλασικό παράδειγμα που έχει σχέση με το γεγονός ότι οι function
pointers δεν «χωράνε» απαραίτητα σε `void *' pointers, αλλά μπορούν να
χωρέσουν σε ένα άλλο function pointers είναι τα «memory models» του
MS-DOS.

Οι pointers σε functions πρέπει να μπορούν να δείξουν σε όλο το address
space του εκτελέσιμου κώδικα του προγράμματος, ενώ οι `void *' pointers
αρκεί να είναι τόσο μεγάλοι που να χωράνε ένα δείκτη για την περιοχή
δεδομένων του προγράμματος.

Σε ορισμένα μοντέλα μνήμης του DOS, αυτό σημαίνει πως μπορεί οι function
pointers να είναι μεγαλύτερου μεγέθους από τους `void *', π.χ. ένα
function pointer να πρέπει να έχει segment:offset διεύθυνση, όπου
`segment' και `offset' δύο 16-bit τιμές.  Αντίθετα, επειδή το πρόγραμμα
έχει πολύ λίγα δεδομένα δικά του, οι `void *' pointers να είναι απλά της
μορφής `offset'.

Για περισσότερες λεπτομέρειες, αυτή η σελίδα μπορεί να βοηθήσει:

    http://www.scit.wlv.ac.uk/cbook/chap6.msdos.memory.html




More information about the Linux-greek-users mailing list