Thread: Help specifying a specific size type in C++

  1. #1
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901

    Help specifying a specific size type in C++

    I am reading the header of a file and I know to use an unsigned char of 8 bits but what about an 8 byte portion of the header? Do I use an unsigned char[8] or unsigned unsigned char* for data types. I would think if I know the specific size I use an array and if it changes during runtime to dynamically allocate it, but generally what should I use.

    Also I see that the fread function from the C standard library reads into a (void *) data type while the fstream class reads it into a char*. Is it safe to cast an unsigned char* into a char* or should I start off using a char* from the beginning even if it might affect the reading of the byte.

  2. #2
    Registered User Mortissus's Avatar
    Join Date
    Dec 2004
    Location
    Brazil, Porto Alegre
    Posts
    152
    You can use a fixed size array to read the file. However, if your intention is to create an struct to interpret the content of a file you should be aware that the compiler might change the size of the members of the struct to optimize it, for example:

    You define a struct:

    Code:
    struct MyStruct {
        char user_id[5];
        char valid;     
    }
    Then, you read a file into the struct like this:

    Code:
    MyStruct ms;
    read(fd, &ms, sizeof(MyStruct));
    The compiler could change the size of, for example, user_id, to a power of 2, in this case it would be 8. You would read 9 bytes, instead of 6. In gcc, to solve this problem you use #pragma
    Code:
    #pragma pack(1)
    //define your struct here
    #pragma pack
    It is safe to cast from unsigned for reading, for example. You must take care to properly use the data inside the array, if casted.

  3. #3
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901
    well in my case there are several indicators that I ignore so rather then read to the sizeof(MyStruct), I would be reading to the size of the individual members of the struct specifying the size in bytes. The problem I'm running into is if I have an integer value that I need to read from the file.
    Code:
    struct a
    {
       char data1[2];
       int data2;
    }
    
    read(file, (char*)data2, sizeof(data2));
    I get something called a "segmentation fault" during runtime while debugging.

  4. #4
    Registered User
    Join Date
    May 2007
    Posts
    88
    Code:
    read(file, (char*)data2, sizeof(data2));
    
    //Should be this
    read(file, static_cast<char*>(&data2), sizeof data2);

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Mortissus View Post
    The compiler could change the size of, for example, user_id, to a power of 2, in this case it would be 8. You would read 9 bytes, instead of 6. In gcc, to solve this problem you use #pragma
    Code:
    #pragma pack(1)
    //define your struct here
    #pragma pack
    Ack. I'd never recommend changing the packing of a structure just for the "convenience" of being able to read it in a single call. Now you've limited yourself to running on systems where the compiler can pack structures. Just take the hit and read/write the data members individually.

    And if you INSIST on packing the structure, and you're using GCC, don't use a pragma, this is deprecated. Instead use __attribute__((__packed__))

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Or realise that you can never solve the endian problem, even if you manage to fix the alignment problem with various "pack" approaches.

    At which point, read the file as a byte stream and manually add each byte to the appropriate member of the struct.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901
    OK now I'm having a weird problem. When I try to use file.read(data1, 8) it gives me the string and some other weird data when I try to output it. When I use file.get(data1, 9) it gives me the proper input (at least as far as char goes). Should I not be using file.read()? What is the difference between that and file.get() besides the .get() size indicates n-1.
    Last edited by indigo0086; 06-11-2007 at 03:59 PM.

  8. #8
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    I hope you resized data1 accordingly.

    if you read() in data1, and then output it as a string, it won't have the NULL terminator.

  9. #9
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >What is the difference between that and file.get() besides the .get() size indicates n-1
    file.get(data1, 9) will read text of up to 8 characters, and add a string terminator('\0') to the end. file.read(data1, 8) will simply read 8 bytes, but no string terminator is added. All C-style strings require a string terminator, which can be added manually if necessary.

  10. #10
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901
    Then why am I getting these extra characters. For example this is what I get♠

    Code:
    typedef struct
    {
        char title[8];
        char type[8];
        int xpts;
        int ypts;
    } TerrainHeader;
    
    int main()
    {
        TerrainHeader ter;
        std::fstream inputfile("scape.ter", ios::in);
        inputfile.read(ter.title, 8);
        cout << ter.title;
        return 0;
    }
    The output is "TERRAGEN π┬┬w&#182;╕├wx$="

    the 8 bytes should be the string "TERRAGEN" but when I output it it doesn't display properly

  11. #11

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    C style strings indicate their length with a null character that terminates the string. You are reading in 8 bytes for the eight characters, but you never add a null character to indicate the end of the string. In addition, your arrays only have room for eight characters, so if you did add the null character you would be accessing data passed the end of the array.

    This only matters if you are using functions that assume a C style string. For example, operator<< assumes a null-terminated string, so it continues to output until it finds a null. If you aren't going to use the char array with functions expecting a C style string, you can leave it as is.

    When you read in 9 characters, it apparently is reading in a null byte and making your code work?

    Maybe I missed something, but I don't necessarily see the need to use read() and read in binary mode here.
    Last edited by Daved; 06-11-2007 at 04:30 PM.

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    It was just explained to you! Since you're using read(), you need to add the NULL terminator yourself.
    Code:
    int main()
    {
        TerrainHeader ter;
        std::fstream inputfile("scape.ter", ios::in);
        inputfile.read(ter.title, 7);
        ter.title[7] = 0;
        cout << ter.title;
        return 0;
    }
    "TERRAGEN" cannot fit into a char array with 8 characters. You need 9 with the NULL. So:
    Code:
    typedef struct
    {
        char title[9];
        char type[8];
        int xpts;
        int ypts;
    } TerrainHeader;
    
    int main()
    {
        TerrainHeader ter;
        std::fstream inputfile("scape.ter", ios::in);
        inputfile.read(ter.title, 8);
        ter.title[8] = 0;
        cout << ter.title;
        return 0;
    }
    Or you could simplify things and just use get().
    Code:
    typedef struct
    {
        char title[9];
        char type[8];
        int xpts;
        int ypts;
    } TerrainHeader;
    
    int main()
    {
        TerrainHeader ter;
        std::fstream inputfile("scape.ter", ios::in);
        inputfile.get(ter.title, 9);
        cout << ter.title;
        return 0;
    }
    [edit] Three replies! Wow. I was too busy adding colour to my post . . . [/edit]
    [edit=2] Make that four replies. [/edit]
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  14. #14
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    > char title[8];
    This should be:
    Code:
        char title[9];
    To make room for the string terminator.
    > inputfile.read(ter.title, 8);
    Now add the string terminator to make it a string:
    Code:
        inputfile.read(ter.title, 8);
        ter.title[inputfile.gcount()] = '\0';

  15. #15
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901
    ah, how dumb of me. But it's perfectly ok to use read for non string data?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. char Handling, probably typical newbie stuff
    By Neolyth in forum C Programming
    Replies: 16
    Last Post: 06-21-2009, 04:05 AM
  2. failure to import external C libraries in C++ project
    By nocturna_gr in forum C++ Programming
    Replies: 3
    Last Post: 12-02-2007, 03:49 PM
  3. Please Help - Problem with Compilers
    By toonlover in forum C++ Programming
    Replies: 5
    Last Post: 07-23-2005, 10:03 AM
  4. ras.h errors
    By Trent_Easton in forum Windows Programming
    Replies: 8
    Last Post: 07-15-2005, 10:52 PM
  5. Learning OpenGL
    By HQSneaker in forum C++ Programming
    Replies: 7
    Last Post: 08-06-2004, 08:57 AM