2011-12-25 4 views
1

몇 주 전, 나는 (내가 그들을 사용하는 데 사용하고 있지 않다) 수레 , 처음 복식를 사용하고, 나는이 비교 피연산자에 대한 몇 가지 문제점. 그 유형에 값을 할당하려고 할 때도 문제가 있었지만 해결했습니다 ...'부호없는 long int와'및 '부호 없음 long long int와'할당 문제

오늘 저는 C++로 라이브러리를 만들고 있는데, 오류를 발견했습니다 ... 잘 ... 이상한? 아니면 내 바보 같은 생각이야?

ini::ini(const char * path, bool _autoflush_ /*= false*/) { 
/* Storing file name ... */ 
f_name = new char[strlen(path)+1]; 
strcpy(f_name, path); 

/* Storing autoflush ... */ 
autoflush = _autoflush_; 

/* First step: getting file size */ 
    /* Open the file in read/append mode */ 
    FILE * fd = fopen(path, "r"); 
    /* On non-valid descriptor, goto next step directly */ 
    if(fd == NULL) f_size = 1; goto allocbuffer; 

    /* Seek to the end */ 
    fseek(fd, 0, SEEK_END); 
    /* Get file size */ 
    f_size = (unsigned long int)ftell(fd) + 1; 

/* Second step: allocating memory for the buffer */ allocbuffer: 
    cout << endl << endl << endl << endl << "Wanting " << sizeof(char)*f_size << " bytes of memory!" << endl << endl << endl << endl; 
    /* Allocate buffer-space */ 
    buffer = (char*)malloc(sizeof(char)*f_size); 
    if(buffer == NULL) { 
     errord = (char*)malloc(strlen(INI_ERROR_NOT_ENOUGH_MEMORY) + 1); 
     strcpy(errord, INI_ERROR_NOT_ENOUGH_MEMORY); 
     cout << endl << endl << endl << endl << "Last error: \"" << errord << "\"." << endl << endl << endl << endl; 
     return; 
    } 
    /* Initialize and fill it with null bytes */ 
    memset(buffer, 0, f_size); 
    /* Goto next step */ 
    if(fd == NULL) goto endconstruct; 

/* Third step: storing in the buffer */ loadbuffer: 
    /* Rewind file descriptor */ 
    rewind(fd); 
    /* Read from file */ 
    if(fread(buffer, 1, f_size, fd) != f_size) { 
     errord = (char*)malloc(strlen(INI_ERROR_NOT_READED) + 1); 
     strcpy(errord, INI_ERROR_NOT_READED); 
     cout << endl << endl << endl << endl << "Last error: \"" << errord << "\"." << endl << endl << endl << endl; 
     cout << endl << endl << endl << endl << "BYTES OF FILE: \"" << f_size << "\"." << endl << endl << endl << endl; 
    } 
    /* Close file descriptor */ 
    fclose(fd); 
    /* Get number of lines */ 
    f_line = strnum(buffer, "\n") + 1; 

/* End building of object */ 
endconstruct: 
    /* Print out what is stored in the buffer NOW */ 
    cout << endl << endl << endl << endl << "Buffer is:" << endl << buffer << endl << endl << endl << endl; 

return; 

} 아마 INI 라이브러리가 이미 생성되어

, 그리고 훨씬 더 내 이상 :

는 코드입니다. 하지만 저는 C에서 C++을 배우기 시작했습니다. 흥미롭고 유용한 것으로 연습하고 싶습니다. 내가 여기에 붙여 넣기하는 것이 필요하지만, 여기 경우 나도 몰라, 클래스 선언을 놓친 : 몇 가지 '테스트'후

/** @def INI_ERROR_NOT_READED 
    @brief <em>Not readed as many bytes as required</em> 
*/ 
#define INI_ERROR_NOT_READED "Not readed as many bytes as required" 
/** @def INI_ERROR_NOT_ENOUGH_MEMORY 
    @brief <em>There is not enough memory</em> 
*/ 
#define INI_ERROR_NOT_ENOUGH_MEMORY "There is not enough memory" 

/** @class ini 
    @brief Class to describe <em>ini</em> files. 

    It describes an ini file. All the file is readed and loaded 
    in memory, for faster access. This class is the 
    improved & C++ version of the old, monstruous 
    functions defined in the old, monstruous IO Utilities 
    Library. Writting functions use dynamic memory reallocation 
    and file flush to the filesystem. 
*/ 
class ini { 
    public: 
     /** @brief Constructor. Gives initial memory for the buffer and loads all the file in that buffer. 
     * 
     * @param path - Path of the <em>ini</em> file to open. 
     * @param _autoflush_ - Whether to auto-flush changes to hard disk or not. 
     * If you don't set it to any value, <em>false</em> is taked as default 
     * value and you have to flush changes manually using member function flush(). 
     * Setting it to <em>true</em> may make it less efficient, so be careful 
     * if you're going to make a lot of changes in the <em>ini</em> file. 
     */ 
     ini      (const char * path, bool _autoflush_ = false); 
     /** @brief Destructor. Frees the memory pointed by <em>buffer</em> and destroys the #ini object. 
     * 
     * It's very important to free the memory buffer, to avoid memory corruptions. 
     */ 
     ~ini     (void); 
     /** @brief Gets last error stored in private member <em>errord</em>. 
     * 
     * @return Last error-descriptor as string. 
     */ 
     char *  geterror (void); 
     /** @brief Flush changes made in the buffer to the hard disk. 
     * 
     * You can do it manually or set auto-flushing by the second argument of 
     * ini::ini(). 
     * 
     * @par Example of usage: 
     * @code 
     * ini inid("myini.ini"); 
     * // make changes 
     * inid.flush(); 
     * @endcode 
     */ 
     void  flush  (void); 
     /** @brief Flush changes made in the buffer to *another* file the hard disk. 
     * 
     * Using this function instead of normal flush(void), you are able to 
     * save the buffer to another #ini file that is not the original one. 
     * 
     * @par Example of usage: 
     * @code 
     * ini inid("myini.ini"); 
      * // make changes 
     * inid.flush("myini.backup.ini"); 
     * @endcode 
     */ 
     void  flush  (const char * path); 
     /** @brief Checks if a section exists. 
     * 
     * @param tsection - The name of the section to check, without the braces. 
     * 
     * @return #true if the section exists; #false if not. 
     */ 
     bool  sectExists (const char * tsection); 
     /** @brief Gets the line in that a section starts. 
     * 
     * @param tsection - The name of the section to check, without the braces. 
     * 
     * @return The line in that the section starts; -1 if not-founded section. 
     * Keep in mind that the first line is 1, the second, 2,... 
     */ 
     int   sectStart (const char * tsection); 
     /** @brief Gets the line in that a section ends. 
     * 
     * @param tsection - The name of the section to check, without the braces. 
     * 
     * @return The line in that the section ends; -1 if not-founded section. 
     * Keep in mind that the first line is 1, the second, 2,... 
     */ 
     int   sectStop (const char * tsection); 
     /** @brief Checks if a key exists. 
     * 
     * @param tsection - The name of the section to check, without the braces. 
     * If the key is outside any section (if it's a #KWOS), then <em>tsection</em> 
     * should be #KWOS. 
     * @param tkey - The name of the key to check. 
     * 
     * @return #true if the key exists in the specified section; #false if not. 
     */ 
     int   keyExists (const char * tsection, const char * tkey); 
     /** @brief Reads the value of a key as a string. 
     * 
     * @param tsection - The name of the section to read from, without the braces. 
     * If the key is outside any section (if it's a #KWOS), then <em>tsection</em> 
     * should be #KWOS. 
     * @param tkey - The name of the key to read its value. 
     * @param tval - The default string to return if cannot found the key. 
     * 
     * @return The value of the key <em>tkey</em> in section <em>tsection</em>; or 
     * <em>tval</em> when non-existing key. 
     */ 
     char *  read  (const char * tsection, const char * tkey, const char * tval); 
     /** @brief Reads the value of a key as an integer value. 
     * 
     * @param tsection - The name of the section to read from, without the braces. 
     * If the key is outside any section (if it's a #KWOS), then <em>tsection</em> 
     * should be #KWOS. 
     * @param tkey - The name of the key to read its value. 
     * @param tval - The default value to return if cannot found the key. 
     * 
     * @return The value of the key <em>tkey</em> in section <em>tsection</em>; or 
     * <em>tval</em> when non-existing key. 
     */ 
     long int readi  (const char * tsection, const char * tkey, int tval); 
     bool  delKey  (const char * tsection, const char * tkey); 
     bool  delSect  (const char * tsection); 
     bool  write  (const char * tsection, const char * tkey, const char * tval); 
     bool  write  (const char * tsection, const char * tkey, int tval); 
    private: 
     unsigned long int  f_size; /**< File size. */ 
     unsigned int   f_line; /**< Number of lines of the <em>ini</em> file. */ 
     char *     buffer; /**< Memory buffer to store data. Dynamimcally reallocated. */ 
     char *     f_name; /**< File name. */ 
     bool     autoflush; /**< Whether to auto-flush to hard disk or not. */ 
     char *     errord; /**< Last error stored internally by the functions of the #ini class. */ 
}; 

, 나는 마침내 문제가 'f_size'에 있음을 발견했다 변하기 쉬운. 왜? 모르겠다. 하지만, 표준 출력으로 출력하면 매우 큰 숫자가 표시됩니다. 그것은 메모리 할당 (malloc의 경우) 오류와 파일 (또는 memset을 사용한 초기화)에서 읽는 오류입니다.

도움을 많이 받으실 수 있습니다. 그리고 링크, ref 또는 설명을 통해 내 실수를보고 계속 학습 할 수 있습니다.

감사합니다.

추신 : 저는 Linux Debian "squeeze"에서 g ++을 사용하고 있습니다, amd64. 파일 이 존재하지

if(fd == NULL) f_size = 1; goto allocbuffer; 

경우, 논리는 여전히 allocbuffer 레이블로 점프 :

+2

BTW'strlen'과'new char []'? 'malloc'조차요? 여전히 C로 생각하고 있고,'std :: string'을 사용하고 번영하다. – Kos

+0

그러나 많은 함수들이 '여전히'_const char * _와 _char * _...를 사용했다는 것을 알았고 동적으로 메모리를 재 할당하기 위해 _realloc_가 필요하다. 버퍼 –

+1

컨테이너 클래스를 작성하지 않은 경우 왜 버퍼에 동적으로 재 할당 된 메모리가 필요합니까? – Kos

답변

3

여기에 하나 미묘하지만 중요한 문제입니다.

이 문제를 해결하려면 중괄호를 사용하십시오. 그리고 크리스탈 선명도를 위해 들여 쓰기.

if(fd == NULL) 
{ 
     f_size = 1; 
     goto allocbuffer; 
} 

변수를 올바르게 초기화하지 않았습니다.

2

wallyk에서 지적한 문제 외에도 ftell에 오류가 발생하면 -1을 반환하고 부호없는 long에 캐스팅하면 오버플로가 발생합니다.

어쨌든 don't use ftell to get a file's size입니다. fstat 또는 유사하게 사용하십시오. 대신

f_name = new char[strlen(path)+1]; 
strcpy(f_name, path); 

:

0

내가 여기 당신을위한 코드를 (이 더 codereview.se에 속한다) 디버깅,하지만하지 않습니다는 몇 가지 힌트입니다 std::string로 f_name을 정의하고 할 ...

f_name = path; 

 errord = (char*)malloc(strlen(INI_ERROR_NOT_READED) + 1); 
     strcpy(errord, INI_ERROR_NOT_READED); 
     cout << "Last error: \"" << errord << "\"." << endl; 

는 같은 동적 메모리 할당 그냥 화면에 캐릭터를 작성 있습니까? 가 대신 간단하게 수행

 errord = INI_ERROR_NOT_READED; 
     cout << "Last error: \"" << errord << "\"." << endl; 
또한 버퍼에 전체 파일을 읽고, (에서와 같이, 몇 줄의 코드) 간단한 방법이 있습니다. https://stackoverflow.com/a/2602060/399317을 참조하십시오. 짧은


긴 이야기 : new[]malloc 당신이 당신의 자신의 컨테이너를 작성하지 않는 한 친구 수 없습니다. STL 컨테이너를 대신 사용하십시오 (예 : std::vector, std::string도 유용합니다).

+0

고마워요! 그래서, std :: string을 사용하고 ... @Kos ... 'errord'의 'direct'assignment? 하지만 그때 나는 seg 결함이나 그와 비슷한 것을 갖게 될 것입니다. 포인터는 과거 내 많은 문제의 원인이었습니다 ... 'errord'는 'ini'클래스의 개인 멤버입니다. 그 상황에서 'cout'은 seg fault 전에 인쇄하기위한 것입니다 ... –