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

Ερωτήσεις για C


capoelo

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

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

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

Έχω φρικάρει φίλε DirectX με το συγκεκριμένο... ο 32μπιτος gcc του mingw λειτουργει κανονικά. Αργότερα που θα πάω σπίτι (εκεί έχω την 32μπιτη Pelles, εδώ έχω την 64μπιτη, που λειτουργεί σωστά) θα προσθέσω έναν εξτρα έλεγχο για errno != 0 στην f_size ...

Λοιπόν, σε C++ Builder αφού μετακινηθώ με ένα fseek στην θέση LONG_MAX και ύστερα με ένα fgetc πάω πιο πέρα, σε αρχείο μεγέθους 2.149.797.568 bytes, τότε η ftell επιστρέφει μεν < 0 αλλά όχι το απόλυτο -1L της τεκμηρίωσης αλλά την αρνητική τιμή -2147483648 (oops! ;)) ενώ παράλληλα το errno δεν ενεργοποιείται (όπως όφειλε).

 

Μόνος τρόπος για να διακόψω την διαπέραση του αρχείου (δίχως να το αφήσω να φτάσει σε EOF) είναι με μια συνθήκη < 0 και τίποτε άλλο.

 

(βρε τι μαθαίνω :P)

 

Υ.Γ.

Σε VS 2008 η ftell επιστρέφει -1L, όπως προβλέπεται από την τεκμηρίωση (η δε errno παραμένει ανενεργή).

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Λοιπόν, σε C++ Builder αφού μετακινηθώ με ένα fseek στην θέση LONG_MAX και ύστερα με ένα fgetc πάω πιο πέρα, σε αρχείο μεγέθους 2.149.797.568 bytes, τότε η ftell επιστρέφει μεν < 0 αλλά όχι το απόλυτο -1L της τεκμηρίωσης αλλά την αρνητική τιμή -2147483648 (oops! ;)) ενώ παράλληλα το errno δεν ενεργοποιείται (όπως όφειλε).

 

Μόνος τρόπος για να διακόψω την διαπέραση του αρχείου (δίχως να το αφήσω να φτάσει σε EOF) είναι με μια συνθήκη < 0 και τίποτε άλλο.

 

(βρε τι μαθαίνω :P)

 

Την οποία συνθήκη εγώ (ο καημένος :lol:) την έχω εξαρχής :(

 

ΥΓ. Το άνοιξες ως binary το αρχείο πριν ζητήσεις ftell; Ρωτάω γιατί στη θεωρία για text-files η ftell έχει undefined behaviour.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Την οποία συνθήκη εγώ (ο καημένος :lol:) την έχω εξαρχής :(

 

ΥΓ. Το άνοιξες ως binary το αρχείο πριν ζητήσεις ftell; Ρωτάω γιατί στη θεωρία για text-files η ftell έχει undefined behaviour.

 

Yeap, ως "rb".

 

Υ.Γ.

Κοίταξε, και σε C++ Builder αφού γυρίζω σε αρνητική τιμή (0χFF...) αντί του -1 που δίνει το VS08 δεν αποκλείεται για κάποιο πολύ μεγαλύτερο αρχείο από αυτό που δοκίμασα να γυρίσει κάποια στιγμή και σε θετική τιμή οπότε "μια από τα ίδια".

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Nice :)

 

Στην Pelles32 πάντως είτε κάνω cast αργότερα είτε δεν κάνω καθόλου στην επιστροφή της ftell() δεν επιστρέφει αρνητικό αριθμό ποτέ. Συμπεριφέρεται σαν να είναι unsigned long και κάνει wrap-around. Αν δηλαδή της περάσω ένα αρχείο π.χ. 5.3Gb μου απαντάει πως είναι 1.7Gb :mad:

 

Υ.Γ.

Κοίταξε, και σε C++ Builder αφού γυρίζω σε αρνητική τιμή (0χFF...) αντί του -1 που δίνει το VS08 δεν απολύεται για κάποιο πολύ μεγαλύτερο αρχείο από αυτό που δοκίμασα να γυρίσει κάποια στιγμή και σε θετική τιμή οπότε "μια από τα ίδια".

 

Το γαμότο είναι πως αυτή η συνάρτηση είναι ο μοναδικός portable κώδικας για να πάρεις το μέγεθος ενός αρχείου. Την χρησιμοποιώ στον hexviewer ώστε αρχεία μικρότερα του LONG_MAX να γίνοnται malloc'ed μονοκόμματα, ενώ για τα μεγαλύτερα (όταν δλδ η f_size() επιστρέφει 0) κάνω malloc σε τμήματα με realloc ...οπότε το συγκεκριμένο πρόβλημα μου έχει καταστρέψει όλο το κόνσεπτ.

 

Εν τω μεταξύ, το run-time της Pelles-C μπορεί και κάνει realloc πολύ μεγαλύτερα τμήματα μνήμης από ότι του mingw-gcc (που χρησιμοποιεί νομίζω του vs)... αυτό τα παίζει περίπου στο 1.5Gb (με τμήματα των 100Mb) ... η Pelles-C μου έκανε μέχρι 3Gb πριν τα φτύσει.

 

γαμώ τον portable κώδικα μέσα γαμώ :(

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

3.Όποτε τρέχω ένα πρόγραμμα,το αποτέλεσμα εμφανίζεται για λίγο και μετά σβήνει.Ποια εντολή μπορώ να χρησιμοποιήσω για να το αποτρέψω;

 

Ελπίζω να μην έγινα κουραστικός.Ευχαριστώ προκαταβολικά.

 

Μπορεις να χρησιμοποιησεις την εντολη system("pause");

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Nice :)

 

Στην Pelles32 πάντως είτε κάνω cast αργότερα είτε δεν κάνω καθόλου στην επιστροφή της ftell() δεν επιστρέφει αρνητικό αριθμό ποτέ. Συμπεριφέρεται σαν να είναι unsigned long και κάνει wrap-around. Αν δηλαδή της περάσω ένα αρχείο π.χ. 5.3Gb μου απαντάει πως είναι 1.7Gb :mad:

 

Σίγουρα συμπεριφέρεται διαφορετικά από ό,τι θα περιμέναμε αλλά δεν είναι απαραίτητα λάθος αυτή η συμπεριφορά. Η ftell πρέπει να επιστρέψει το offset εκτός και ΑΝ αποτύχει οπότε επιστρέφει -1. Αν κρίνουμε από αυτό που λες ότι παίζει για 5.3GB (το οποίο είναι μεγαλύτερο και από unsigned 32bit) τότε ίσως εσωτερικά οι συναρτήσεις να χρησιμοποιούν 64bits (κάτι σαν το _FILE_OFFSET_BITS=64 της glibc) οπότε τυπικά η ftell "επιτυγχάνει" άρα δεν επιστρέφει -1 αλλά την τιμή η οποία γίνεται wrap. Εννοείται πως δεν έχω στοιχεία για την συμπεριφορά που περιγράφω και μπορεί να δουλεύει τελείως διαφορετικά.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Σίγουρα συμπεριφέρεται διαφορετικά από ό,τι θα περιμέναμε αλλά δεν είναι απαραίτητα λάθος αυτή η συμπεριφορά. Η ftell πρέπει να επιστρέψει το offset εκτός και ΑΝ αποτύχει οπότε επιστρέφει -1. Αν κρίνουμε από αυτό που λες ότι παίζει για 5.3GB (το οποίο είναι μεγαλύτερο και από unsigned 32bit) τότε ίσως εσωτερικά οι συναρτήσεις να χρησιμοποιούν 64bits (κάτι σαν το _FILE_OFFSET_BITS=64 της glibc) οπότε τυπικά η ftell "επιτυγχάνει" άρα δεν επιστρέφει -1 αλλά την τιμή η οποία γίνεται wrap. Εννοείται πως δεν έχω στοιχεία για την συμπεριφορά που περιγράφω και μπορεί να δουλεύει τελείως διαφορετικά.

 

Λίγο "χλωμό" το βλέπω να παίζει κάτι τέτοιο, γιατί είναι δηλωμένη ως long int η ftell (off_t είναι η ftello, που στην pelles είναι _off_t & _ftello(), ως extension... που πράγματι δεν είναι στάνταρ συναρτήσεις αυτές). Θα δοκιμάσω πάντως να αναθέσω απευθείας την ftell() σε έναν uintmax_t για να επιβεβαιώσουμε/διαψεύσουμε αυτό που σκέφτηκες.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Λίγο "χλωμό" το βλέπω να παίζει κάτι τέτοιο, γιατί είναι δηλωμένη ως long int η ftell (off_t είναι η ftello, που στην pelles είναι _off_t & _ftello(), ως extension... που πράγματι δεν είναι στάνταρ συναρτήσεις αυτές). Θα δοκιμάσω πάντως να αναθέσω απευθείας την ftell() σε έναν uintmax_t για να επιβεβαιώσουμε/διαψεύσουμε αυτό που σκέφτηκες.

 

Ναι φυσικά είναι δηλωμένη να επιστρέφει long. Αυτό που εννοούσα είναι πώς υλοποιείται η συνάρτηση ασχέτως τι επιστρέφει. Για παράδειγμα στο linux που δοκίμασα να δω τι επιστρέφει, επιστρέφει μεν -1 και EOVERFLOW αλλά μόνο αν έχω κάνει compile με _FILE_OFFSET_BITS=64. Διαφορετικά δεν ανοίγει καν το αρχείο η fopen.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ναι φυσικά είναι δηλωμένη να επιστρέφει long. Αυτό που εννοούσα είναι πώς υλοποιείται η συνάρτηση ασχέτως τι επιστρέφει. Για παράδειγμα στο linux που δοκίμασα να δω τι επιστρέφει, επιστρέφει μεν -1 και EOVERFLOW αλλά μόνο αν έχω κάνει compile με _FILE_OFFSET_BITS=64. Διαφορετικά δεν ανοίγει καν το αρχείο η fopen.

 

Σε λίγο που θα πάω σπίτι, θα φτιάξω ένα πρόχειρο test-prog που να εφαρμόζει την f_size() στο 1ο του command-line argument και να τυπώνει το μέγεθος (και θα επανέλθω... υπολογίστε καμιά ωρίτσα... ίσως και παραπάνω... μέχρι να πάω σπίτι, να κάνω μπανάκι και να φάω :) )

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Έκανα κάθε πιθανό κι απίθανο συνδυασμό που θα μπορούσα να σκεφτώ, χωρίς επιτυχία...

 

>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>
#include <errno.h>

/*********************************************************//**
* 
*************************************************************
*/
bool f_exists(const char *fname)
{
FILE *fp = fopen(fname, "rb");
if ( !fp )
	return false;

fclose(fp);
return true;
}

/*********************************************************//**
* @brief	Return the size of a file in bytes, or 0 on error
*		(cannot be more than LONG_MAX).
*************************************************************
*/
uintmax_t f_size( const char *fname )
{
long long int size = 0;
FILE 	*fp;

if ( NULL == (fp = fopen(fname, "rb")) )	/* binary mode */
	return 0;

if ( 0 != fseek(fp, 0L, SEEK_END) ) {
	fclose(fp);
	return 0;
}

size = (long long int)ftell(fp);
perror(NULL);
printf( "size = %lld\n", size );
fclose(fp);

return (errno != 0 || size < 0) ? 0 : (uintmax_t)size;
}

/* --------------------------------------------------------------------------------- */
int main( int argc, char *argv[]  )
{
//	uintmax_t fsize = 0;

if ( 1 == argc ) {
	fputs( "*** no data!\n", stderr );
	goto ret_fatal;
}

if ( !f_exists(argv[1]) ) {
	fputs( "*** non-existent file!\n", stderr );
	goto ret_fatal;
}

printf( "file size: %"PRIuMAX"\n",  f_size(argv[1]) );


system("pause");				/* windows only */
exit(EXIT_SUCCESS);

ret_fatal:
system("pause");				/* windows only */
exit(EXIT_FAILURE);

}

Έχω αφήσει μια δοκιμή με long long int στον κώδικα της f_size. Ότι και να κάνω, κάνει wrap around (τελικά ο mingw32 gcc κάνει fail() στην fseek για αρχεία μεγαλύτερα του LONG_MAX, και όχι στην ftell() που έγραψα σε προηγούμενα post... δεν φτάνει καν στην ftell() )

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

 

 

Θες να πεις ότι εσείς δεν έχετε κολλημένο στο γραφείο ένα χαρτάκι με τα promotions και άλλο με operator precedence ? :)

Το οποίο είναι κολλημένο πάνω από χαρτάκι για συντομεύσεις (vi, emacs κτλ) που, αραιά και που, το σηκώνουμε λίγο για να δούμε από κάτω :D :D :D

 

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το πρόβλημα είναι πως αυτό ο κώδικας της f_size() είναι ο μόνος portable σε όλες τις πλατφόρμες φίλε DirectX.

 

Φίλε migf1 δεδομένης της κατάστασης όμως θα μπορούσες να βασιστείς σε *συναρτήσεις POSIX, οι οποίες αν δεν υποστηρίζονται συνολικά από τις πιο γνωστές πλατφόρμες, οπωσδήποτε παρέχουν υποστήριξη στις πιο βασικές , όπως για παράδειγμα η stat η οποία μεταξύ άλλων επιστρέφει το μέγεθος του αρχείου (και σε BC++ επιστρέφει επίσης αρνητική τιμή για MAX_LONG + 1 μεγέθους αρχεία).

 

*Επίσης ρίξε μια ματιά και στις ρουτίνες fsetpos/ fgetpos, για παράδειγμα σε BC++, πάω με fseek στο MAX_LONG του αρχείου, μετακινούμε +1 θέση και ύστερα λαμβάνω την θέση με fgetpos. Το fpos_t είναι μορφής LONG (σε BC++ πάντα) οπότε έχει γυρίσει σε αρνητική τιμή, δες αν συμβαίνει το ίδιο στους compiler σου. Επίσης δοκίμασε και την fsetpos μήπως έχεις καλύτερα αποτελέσματα.

 

*Αυτά με την ελπίδα ότι εσωτερικά δεν καταλήγουν σε κάποιο ftell/fseek κλπ.

 

Υ.Γ.

Εγώ στην θέση σου, θα καλούσα σε LL επίπεδο συνάρτηση του Λ.Σ. και όποιος ήθελε, κατά το port, ας πρόσφερε την ανάλογη συνάρτηση του δικού του Λ.Σ. -μέχρι ότου οι συναρτήσεις της C διορθωθούν. Το έχω δει ως πρακτική σε αρκετά Open Source projects που έχουν γίνει port σε πολλές πλατφόρμες.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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