Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

  • Απαντ. 1,6k
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.

Οπότε πρέπει να μας δώσεις περισσότερο κώδικα, διότι αυτός που δίνεις δεν επαρκεί για να καταλάβουμε τι μπορεί να πηγαίνει στραβά (π.χ. δεν ξέρουμε τι κάνεις με τα list και dummy μέσα στην Delete() ).

 

EDIT:

 

Με το Eclipse έβγαλες άκρη τελικά;

Δημοσ.

Oχι δεν το εψαξα καθολου...δεν βρηκα χρονο...

>
Bool SSLDelete(type *list, type *node) {
while (list->next && list->next != node)
 list = list->next;
if (list->next) {
 list->next = node->next;
 free(node);
 return TRUE;
} else
 return FALSE;
}

Δημοσ.

Πολύ πρόχειρα βλέπω πως τον δείκτη list τον δηλώνεις by-val στα ορίσματα της SSLDelete(), αλλά όταν την καλείς μάλλον τον περνάς by-ref (δεν έχω επαρκή πληροφόρηση για το πως είναι ορισμένος πριν τη κλήση της SSLDelete(), αλλά από τα συμφραζόμενα φαίνεται να τον περνάς by-ref ).

Δημοσ.

Και αυτο το εγραψα λαθος εδω(by ref ειναι το list)...Τεσπα θα το ξανα κοιταξω και αν ειναι θα στειλω πιο συγκεκριμενες αποριες...Ευχαριστω

Δημοσ.

@imitheos:

 

Τελικά έχω παρερμηνεύσει κάτι σχετικά με το πρότυπο και την αρχική σου παρατήρηση (btw, που χάθηκες ρε συ);

 

Επίσης, θα μπορούσες όταν ευκαιρήσεις (ή όποιος άλλος) να εξηγήσεις τι εννοεί το απόσπασμα του προτύπου σχετικά με το union, γιατί δεν καταλαβαίνω... γρι;

 

 

 

Δημοσ.

@imitheos:

 

Τελικά έχω παρερμηνεύσει κάτι σχετικά με το πρότυπο και την αρχική σου παρατήρηση (btw, που χάθηκες ρε συ);

 

Επίσης, θα μπορούσες όταν ευκαιρήσεις (ή όποιος άλλος) να εξηγήσεις τι εννοεί το απόσπασμα του προτύπου σχετικά με το union, γιατί δεν καταλαβαίνω... γρι;

 

>
int my2d[2][3] = { {1,2,3}, {4,5,6} };
int *p;
union mitsos {
 int arr2d[2][3];
 int arr1d[6];
};
p = ((union mitsos *)&my2d)->arr1d;

 

Εκτός από δείκτη σε συμβατό τύπο (δηλαδή στον ίδιο δισδιάστατο με τον οποίο έχει δηλωθεί αρχικά ο πίνακας) και με δείκτη σε char μπορείς να χρησιμοποιήσεις union. Μπορείς δηλαδή να κάνεις cast τον δισδιάστατο πίνακά σου σε ένα union που περιέχει και τις δύο "μορφές" πίνακα και μετά να θέσεις την διεύθυνση του μονοδιάστατου σε ένα απλό δείκτη σε int. Στο περίπου δηλαδή όπως φαίνεται στον παραπάνω code. Επειδή το union εμπεριέχει τον σωστό τύπο (τον δισδιάστατο) επιτρέπεται να κάνεις cast τον πίνακα και έπειτα απλά χρησιμοποιείς την μονοδιάστατη μορφή. Όμως για να είσαι σίγουρος θέλεις C99 και πέρα.

Δημοσ.

Thanks για την εξήγηση (a bit complicated, indeed :))

 

Συνεχίζω όμως να διατηρώ επιφυλάξεις για την ακαταλληλότητα των (non-char *) και πιο συγκεκριμένα ακόμα και σε σύγκριση με το απόσπασμα του προτύπου που παράθεσες.

 

Στο δικό μου αντίγραφο του προτύπου, αναφέρονται τα εξής:

 

 

 

WG14/N1256 Committee Draft — Septermber 7, 2007 ISO/IEC 9899:TC3

...

6.5 Exressions

...

6. The effective type of an object for an access to its stored value is the declared type of the object, if any. [75]) If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one.

 

For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

 

[75] Allocated objects have no declared type.

 

7. An object shall have its stored value accessed only by an lvalue exression that has one of the following types: [76])

  • a type compatible with the effective type of the object,
  • a qualified version of a type compatible with the effective type of the object,
  • a type that is the signed or unsigned type corresponding to the effective type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
  • a character type

 

[76] The intent of this list is to specify those circumstances in which an object may or may not be aliased.

 

...

 

6.5.4 Cast operators

 

Syntax

>
1. cast-exression:
   unary-exression
       ( type-name ) cast-exression

 

Constraints

 

2. Unless the type name specifies a void type, the type name shall specify qualified or unqualified scalar type and the operand shall have scalar type.

 

3. Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast.

 

Semantics

 

4. Preceding an exression by a parenthesized type name converts the value of the exression to the named type. This construction is called a cast. [89] A cast that specifies no conversion has no effect on the type or value of an exression.

 

5. If the value of the exp<b></b>ression is represented with greater precision or range than required by the type named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the exression is the same as the named type.

 

Forward references: equality operators (6.5.9), function declarators (including prototypes) (6.7.5.3), simple assignment (6.5.16.1), type names (6.7.6).

 

[89] A cast does not yield an lvalue. Thus, a cast to a qualified type has the same effect as a cast to the unqualified version of the type.

 

 

 

Δηλαδή, όπως το ερμηνεύω εγώ (ενδεχομένως λανθασμένα), το casting είναι ακριβώς αυτό που εξασφαλίζει τη συμβατότητα των τύπων του stored value.

 

Επίσης, από το c-faq 6.3 ...

 

 

 

Question 6.3 http://c-faq.com/aryptr/aryptrequiv.html

...

Specifically, the cornerstone of the equivalence is this key definition:

 

A reference to an object of type array-of-T which appears in an exp<b></b>ression decays (with three exceptions) into a pointer to its first element; the type of the resultant pointer is pointer-to-T.

 

That is, whenever an array appears in an exp<b></b>ression, the compiler implicitly generates a pointer to the array's first element, just as if the programmer had written &a[0]. (The exceptions are when the array is the operand of a sizeof or & operator, or is a string literal initializer for a character array. [footnote] See questions 6.23, 6.12, and 1.32, respectively.)

 

As a consequence of this definition, and in spite of the fact that the underlying arrays and pointers are quite different, the compiler doesn't apply the array subscripting operator [] that differently to arrays and pointers, after all.[footnote] Given an array a and pointer p, an exp<b></b>ression of the form a causes the array to decay into a pointer, following the rule above, and then to be subscripted just as would be a pointer variable in the exp<b></b>ression p (although the eventual memory accesses will be different, as explained in question 6.2). If you were to assign the array's address to the pointer:

 

p = a;

 

then p[3] and a[3] would access the same element.

 

This harmony of access explains how pointers can access arrays, serve in their stead as function parameters (see question 6.4), and simulate dynamic arrays (see question 6.14).

 

 

 

EDIT:

 

Απλώς σαν συμπληρωματική πληροφορία, η μέθοδος αυτή με το walk είναι επί της ουσίας αυτή που σε αυτό το άρθρο ισοδυναμεί με την μέθοδο 9 (η οποία πάνω-κάτω ισοδυναμεί με την μέθοδο 8).

 

Αυτές οι 2 μέθοδοι είναι κατά κανόνα ταχύτεροι (επιθυμητό σε σε speed-critical εφαρμογές) όπως φαίνεται και στα benchmarks του άρθρου (χρώματα γκρι και μαύρο, για τις μεθόδους 9 και 8 αντίστοιχα).

Δημοσ.

Συνεχίζω όμως να διατηρώ επιφυλάξεις για την ακαταλληλότητα των (non-char *) και πιο συγκεκριμένα ακόμα και σε σύγκριση με το απόσπασμα του προτύπου που παράθεσες.

 

Επίσης, από το c-faq 6.3 ...

 

Ναι όμως η 6.3 επειδή εξηγεί το "decaying" μιλάει μόνο για μονοδιάστατους οπότε όσα λέει είναι σωστά.

 

Δες τι λέει και η 6.19 που περιγράφει ακριβώς αυτό που λέμε.

 

It must be noted, however, that a program which performs multidimensional array subscripting ``by hand'' in this way is not in strict conformance with the ANSI C Standard; according to an official interpretation, the behavior of accessing (&array[0][0])[x] is not defined for x >= NCOLUMNS.

Όταν περνάς τη διεύθυνση του 1ου στοιχείου και μετά διατρέχεις τις διευθύνσεις σαν να ήταν "flat" ο πίνακας δηλαδή μονοδιάστατος, όταν περάσεις NCOLUMNS στοιχεία δηλαδή την 1η γραμμή, τότε η συμπεριφορά είναι αόριστη.

 

Απλώς σαν συμπληρωματική πληροφορία, η μέθοδος αυτή με το walk είναι επί της ουσίας αυτή που σε αυτό το άρθρο ισοδυναμεί με την μέθοδο 9 (η οποία πάνω-κάτω ισοδυναμεί με την μέθοδο 8).

 

Αυτές οι 2 μέθοδοι είναι κατά κανόνα ταχύτεροι (επιθυμητό σε σε speed-critical εφαρμογές) όπως φαίνεται και στα benchmarks του άρθρου (χρώματα γκρι και μαύρο, για τις μεθόδους 9 και 8 αντίστοιχα).

 

Καλά τα λέει το άρθρο. Συγκρίνει όλες τις "κοινές", όπως αναφέρει, μεθόδους προσπέλασης και προτείνει την πιο γρήγορη. Δηλαδή προτείνει κάτι πρακτικό για να το χρησιμοποιεί ο κόσμος. Δεν αναφέρει πουθενά ότι σκοπεύει σε πλήρη τήρηση του προτύπου. Άσε που θα μπορούσε ακόμη και να το πει γιατί δεν έχω δει καμμία υλοποίηση να συμπεριφέρεται όπως περιέγραψα αρχικά (θα ήταν χαζό άλλωστε).

 

Αυτό πάντως το θέμα με τους πίνακες που μας έφαγε τόση ώρα είναι απλό. Κάτσε να συζητήσουμε για unions (όταν ανέφερα το τρόπο με τη union αν πρόσεξες ανέφερα ότι θέλει c99 και πέρα) να δεις τι χαμός γίνεται εκεί :P

 

Για να μη θαφτεί η ερώτηση του nik234, να αναφέρω πάλι ότι αν δουλεύει κάποιος eclipse σε windows ας γράψει πως μπορούν να εμφανιστούν αναλυτικά τα μηνύματα λάθους του project.

Δημοσ.

Ναι. Δηλαδη σου λεει οτι συμφωνα με την αυστηρη θεωρια αν εσυ περάσεις έναν 2D array σε μια συναρτηση τοτε αυτος

μεταφραζεται σαν ενας δεικτης σε πινακα μήκους δευτερης διάστασης. Την πρωτη μπορουμε να την παραλειψουμε εχουμε χιλιοπεί :P

 

Αν δηλαδη έχεις

 

>

#include<stdio.h>
void func( int [][3]);

int main(void)
{

int arr2d[2][3] = { { 1 , 2 , 3 } , { 4 , 5 , 6 } ;

func( arr2d ) ;

return 0;
}

void func( arr2d [2][3] )
{
int *p= NULL;

for( p = *arr2d ; p < *arr2d + 6; p++)
printf(" %d " , *p);

}

 

Toτε αν εχω καταλαβει καλα ο πινακας {4,5,6}

θεωρειται αοριστη συμπεριφορα απο το προτυπο αλλα δουλευει επειδη αυτοι που εχουν φτιαξει

τον compiler δεν ειναι βλαμμένοι :P

 

Mε απλα λογια χωρις αλλη εμπλοκη των αγγλικων απο το προτυπο για να εξαχθεί και ενα τελικο συμπερασμα .

 

Thanks για την εξήγηση (a bit complicated, indeed :))

 

Συνεχίζω όμως να διατηρώ επιφυλάξεις για την ακαταλληλότητα των (non-char *) και πιο συγκεκριμένα ακόμα και σε σύγκριση με το απόσπασμα του προτύπου που παράθεσες.

 

Στο δικό μου αντίγραφο του προτύπου, αναφέρονται τα εξής:

 

 

 

 

 

 

 

Δηλαδή, όπως το ερμηνεύω εγώ (ενδεχομένως λανθασμένα), το casting είναι ακριβώς αυτό που εξασφαλίζει τη συμβατότητα των τύπων του stored value.

 

Επίσης, από το c-faq 6.3 ...

 

 

 

 

 

 

 

EDIT:

 

Απλώς σαν συμπληρωματική πληροφορία, η μέθοδος αυτή με το walk είναι επί της ουσίας αυτή που σε αυτό το άρθρο ισοδυναμεί με την μέθοδο 9 (η οποία πάνω-κάτω ισοδυναμεί με την μέθοδο 8).

 

Αυτές οι 2 μέθοδοι είναι κατά κανόνα ταχύτεροι (επιθυμητό σε σε speed-critical εφαρμογές) όπως φαίνεται και στα benchmarks του άρθρου (χρώματα γκρι και μαύρο, για τις μεθόδους 9 και 8 αντίστοιχα).

 

migf1 εννοεις τον walk που είχες δωσει στον κώδικα με την while για τους δισδιάστατους ? Αυτος ειναι speed efficient ?

 

http://ideone.com/RqdXtf

Δημοσ.

...

Δες τι λέει και η 6.19 που περιγράφει ακριβώς αυτό που λέμε.

Όταν περνάς τη διεύθυνση του 1ου στοιχείου και μετά διατρέχεις τις διευθύνσεις σαν να ήταν "flat" ο πίνακας δηλαδή μονοδιάστατος, όταν περάσεις NCOLUMNS στοιχεία δηλαδή την 1η γραμμή, τότε η συμπεριφορά είναι αόριστη.

 

Ναι, το είχα δει ("according to an official interpretation"). Αυτό ακριβώς το interpretation είναι που συζητάμε κι εδώ (προφανώς εγκυκλοπαιδικά).

 

Βασικά με βλέπεις κι επιμένω, για 2 λόγους:

 

α) Επειδή αποτελεί κοινή (κοινότατη) πρακτική

β) Επειδή αν το δεχτούμε αβασάνιστα αυτό το interpretation, τότε νομίζω πως κάνει defeat (contradict) όλη την έννοια του casting στην C.

 

Συμφωνούμε στο β);

 

@StarLight: Ναι.

Δημοσ.

@migf1

 

sum is : 20

Process returned 0 (0x0) execution time : 0.013 s

Press any key to continue.

 

Aπο τον κώδικα σου με τον walk.

 

Aν συγκριθει με αυτον εδω

 

>
#include<stdio.h>
#define rows 2
#define COLS 3
void arr2d_sumElements( int [][COLS] , int );
int main(void)
{
int arr2d[rows][COLS]= { {1 , 2 , 3 } , { 4 , 5 , 5}};
arr2d_sumElements(arr2d,2);
return 0;
}
void arr2d_sumElements( int arr2d[][COLS], int nrows ){
   int sum = 0 , i , j;

  for(i=0; i<rows; i++)
   for(j=0; j<COLS; j++)

   sum += arr2d[i][j];
   printf(" sum is :  %d " , sum);
}

 

Μην σου πω οτι δινει και λιγοτερο...

 

sum is : 20

Process returned 0 (0x0) execution time : 0.007 s

Press any key to continue.

Δημοσ.

Κώστα, το benchmarking έχει γίνει σχεδόν ολόκληρη επιστήμη (π.χ.: http://download.intel.com/embedded/software/IA/324264.pdf), σίγουρα χρειάζεται συγγραφή custom ρουτίνων μέτρησης (ιδανικά προσαρμοσμένες στην εκάστοτε αρχιτεκτονική του συστήματος) και σίγουρα δεν περιλαμβάνει μέσα του ούτε printf() statements, ούτε i/o γενικότερα.

 

O κώδικας που έγραψα και χαρακτήρισα ως γρήγορο, δεν είναι ούτε δικά μου επινόηση ούτε κάτι καινούριο. Η τεχνική προσπέλασης πολυδιάστατων πινάκων μονοδιάστατα είναι common-ground στις speed-critical εφαρμογές. Επίσης, αν ο compiler είναι καλός, τότε η ενεργοποίηση των optimization flags του μετατρέπουν έτσι κι αλλιώς τα neseted-loops σε 1.

 

Παρεμπιπτόντως, σχετικά με τις ερμηνείες των προτύπων (και πριν απαντήσει ο imitheos αν συμφωνεί ή όχι με το β) του προηγούμενου ποστ μου), θα ήθελα να προσθέσω στο απόσπασμα του imitheoy καθώς και σε αυτά που συμπλήρωσα εγώ, ακόμα ένα απόσπασμα, από το C11 standard (δεν έχω εύκαιρο το C99 εδώ... είναι στο laptop εκείνο).

 

 

 

6.5.2.1 Array subscripting

 

Constraints

 

1. One of the exp<b></b>ressions shall have type ‘‘pointer to complete object type’’, the other

exp<b></b>ression shall have integer type, and the result has type ‘‘type’’.

 

Semantics

 

2. A postfix exp<b></b>ression followed by an exp<b></b>ression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

 

3. Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n ≥ 2) with dimensions i × j × . . . × k, then E (used as other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with dimensions j × . . . × k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).

 

4. EXAMPLE Consider the array object defined by the declaration

 

int x[3][5];

 

Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. In the exp<b></b>ression x, which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually

entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the exp<b></b>ression x[j], that array is in turn converted to a pointer to the first of the ints, so x[j] yields an int.

 

Forward references: additive operators (6.5.6), address and indirection operators

(6.5.3.2), array declarators (6.7.6.2).

 

 

 

Η ερώτηση λοιπόν είναι κατά πόσο τα πρότυπα περιέχουν σημεία ανοιχτά σε διαφορετικές ερμηνείες, ή ακόμα κι αν ενίοτε περιέχουν αντιφάσεις (οι οποίες συνήθως διορθώνονται στα final drafts, ή σε επόμενη έκδοση).

 

 

 

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

 

 

Επισκέπτης
Αυτό το θέμα είναι πλέον κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...