Thread: Hex dump

  1. #1
    Registered User
    Join Date
    Jan 2008
    Posts
    58

    Hex dump

    I got this exercise and I think I've got it done. Can anyone show me how to make it better? It's a program that takes a file and makes a hex dump. The program has to print 10 bytes and the characters that correspond to the bytes. Whitespace is turned into periods. If the file has "a test file", the output should be
    Code:
    61 20 74 65 73 74 20 66 69 6C a.test.fil
    65 00 00 00 00 00 00 00 00 00 e
    This is the code I have now.
    Code:
    #include <ctype.h>
    #include <stdio.h>
    #include <string.h>
    
    #define NBYTES 10 // # of bytes per row
    
    void hex_dump(FILE *fp);
    int load_bytes(FILE *fp, char row[], int size);
    void print_hex(char row[], int n, int limit);
    void print_row(char row[], int n);
    int printable_char(int ch);
    
    int main(void)
    {
        fputs("Select a file: ", stdout);
    
        char filename[BUFSIZ];
    
        if ( fgets(filename, BUFSIZ, stdin) != NULL )
        {
            // Trim '\n' from the filename
            size_t len = strlen(filename);
    
            if ( filename[len - 1] == '\n' )
            {
                filename[len - 1] = '\0';
            }
    
            // Run the hex dump
            FILE *fp = fopen(filename, "r");
    
            if ( fp != NULL )
            {
                hex_dump(fp);
                fclose(fp);
            }
        }
    }
    
    // Print the contents of a file as hex
    void hex_dump(FILE *fp)
    {
        int n;
    
        do
        {
            char row[NBYTES + 1]; // +1 for '\0'
    
            n = load_bytes(fp, row, NBYTES);
    
            if ( n > 0 )
            {
                print_hex(row, n, NBYTES);
                print_row(row, n);
                putchar('\n');
            }
        }
        while ( n > 0 );
    }
    
    // Read up to size bytes into a string
    // Return the number of bytes read
    int load_bytes(FILE *fp, char row[], int size)
    {
        int n = 0;
        int ch;
    
        while ( n < size && (ch = fgetc(fp)) != EOF )
        {
            row[n++] = ch;
        }
    
        row[n] = '\0';
    
        return n;
    }
    
    // Print the hex version of the characters in a string
    void print_hex(char row[], int n, int limit)
    {
        // Always print limit values
        // Use 0 for values past n
        for ( int i = 0; i < limit; ++i )
        {
            int value = row[i];
    
            if ( i >= n )
            {
                value = 0;
            }
    
            printf("%02X ", value);
        }
    }
    
    // Print a display version of the string
    void print_row(char row[], int n)
    {
        for ( int i = 0; i < n; ++i )
        {
            putchar(printable_char(row[i]));
        }
    }
    
    // Make a character printable
    // even if it's whitespace
    int printable_char(int ch)
    {
        if ( isspace(ch) )
        {
            return '.';
        }
        else
        {
            return ch;
        }
    }
    Do any gurus here think it's OK or do I need to try something else?

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    There is nothing that directly catches the eye. I'm sure others might add something, though.
    But overall, I just want to comment on how clean and nice the code looks. It's not often I see beautiful code like that.
    It also stays away from common pitfalls, so I'd say, in comparison to other newbies, you're a master!

    Congratulations on such nice code!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    printable_char should probably accept and return char instead of int. Not important though.
    Wouldn't "isprint" be more correct with regards to replacing unprintable chars with a dot than "isspace"? I think when hex editors show both they usually leave actual space characters alone, and only make non-printable chars into dots.

    Also, I usually find it more convenient when the column with is a power of two, or at least a multiple of four. So, I'd go for 8, 12, or 16 wide instead of 10. Oh I suppose it is designed for 40-column output, so nevermind.

    Not bad anyway.
    Last edited by iMalc; 01-05-2008 at 09:43 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #5
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    1. make it const-correct (http://cprogramming.com/tutorial/const_correctness.html)
    2. return 0;
    3. inspired by 2: turn up your warning levels.

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    230
    Don't flame me if I'm wrong, but aren't all variables supposed to be declared before any other statements in C?

    Because fputs() is called before the declaration of the char[]

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, in C89, though not C99.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Jan 2008
    Posts
    58
    in comparison to other newbies, you're a master!
    Careful, I might start getting a big head.

    FWIW, one I wrote once.
    That's a lot shorter than mine.

    printable_char should probably accept and return char instead of int.
    Why? I was trying to match the ctype.h character functions and used an int but if there's something wrong with that I'll change it.

    Wouldn't "isprint" be more correct with regards to replacing unprintable chars with a dot than "isspace"?
    Shouldn't '\n' be a printable character? "isprint" doesn't think so, but '\n' kept messing up the output before so I used "isspace" to turn it into '.'

    Does that mean make everything that isn't supposed to change const? I remember having problems in C++ doing that once for stuff like "n" or "limit" in print_hex. I don't remember what the problems were though, just that I got compiler warnings.

    return 0;
    Where? I thought I was returning everything I needed to.

    inspired by 2: turn up your warning levels.
    This is the compile line I use.
    Code:
    como --timing --c99 -r -o $FileDir\$FileName.exe $File
    I can't use --strict because I couldn't afford to buy the Dinkumware library for my compiler. I have to use the M$ library and it gives me errors with --strict.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Banana Man View Post
    Does that mean make everything that isn't supposed to change const? I remember having problems in C++ doing that once for stuff like "n" or "limit" in print_hex. I don't remember what the problems were though, just that I got compiler warnings.
    Yes! print_hex for example never changes the argument row, so it should be const!

    Where? I thought I was returning everything I needed to.
    Main should explicitly return 0

    This is the compile line I use.
    Code:
    como --timing --c99 -r -o $FileDir\$FileName.exe $File
    I can't use --strict because I couldn't afford to buy the Dinkumware library for my compiler. I have to use the M$ library and it gives me errors with --strict.
    There are other compilers out there that doesn't even require the use of command line, though they may not support C99. Dev-C++ supports C99, Visual Studio Express is another free compiler, though it doesn't support C99.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    Jan 2008
    Posts
    58
    Main should explicitly return 0
    Why? I thought that C99 and C++ both returned 0 automatically.

    Yes! print_hex for example never changes the argument row, so it should be const!
    I get that part, but what about the sizes? I mean should I do this?
    Code:
    void print_hex(const char row[], const int n, const int limit);
    Or just this?
    Code:
    void print_hex(const char row[], int n, int limit);
    I haven't read much code that does the first one...

    Dev-C++ supports C99
    Not perfectly, that's why I bought Comeau C/C++ after someone told me that it supports C and C++ perfectly.

    Visual Studio Express is another free compiler, though it doesn't support C99.
    That's what I use as the back end, but the library doesn't like C99 so I'm still not set up completely until I get a C99 library. I can't compile C90 at all until I figure out what command line options to use that won't error on the library. I think Dinkumware will solve both those problems, but I don't have $200 to spend on it.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Banana Man View Post
    Why? I thought that C99 and C++ both returned 0 automatically.
    No, C99 requires return 0 explicitly AFAIK. C++ does it implicitly, but many here consider it good practice to explicitly return 0 anyway.

    I get that part, but what about the sizes? I mean should I do this?
    Code:
    void print_hex(const char row[], const int n, const int limit);
    Or just this?
    Code:
    void print_hex(const char row[], int n, int limit);
    I haven't read much code that does the first one...
    Const is just a keyword you can add... if it compiles fine without it, then you can just add it and it will still compile fine (that is, unless you are trying to modify that argument).
    You don't need const on the int parameters, though, since they're passed by value, it's impossible to modify the original data passed to the function. The first argument is another story, however, because it can be modified, thus it should be const.

    That's what I use as the back end, but the library doesn't like C99 so I'm still not set up completely until I get a C99 library. I can't compile C90 at all until I figure out what command line options to use that won't error on the library. I think Dinkumware will solve both those problems, but I don't have $200 to spend on it.
    Really, Visual Studio support C89 perfectly. You don't have to mess around with command lines with the IDE--that's the best thing, as it should be.
    If you simple need C89, all you need is Visual Studio or Dev-C++.
    Or you can consider C++ which is superior to C in all kinds of ways.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    No, C99 requires return 0 explicitly AFAIK.
    That is not true. C99 allows for an implicit return 0, like C++.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    IIRC, there was one change somewhere that return 0 had to be explicit or did I lose something along the way?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    IIRC, there was one change somewhere that return 0 had to be explicit or did I lose something along the way?
    It was the other way round:
    Quote Originally Posted by 5.1.2.2.3 Program termination
    If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    Registered User
    Join Date
    Jan 2008
    Posts
    58
    Should I not be using C99?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Single hex dump - Error codes / Plain errors...
    By Blackroot in forum Windows Programming
    Replies: 4
    Last Post: 04-03-2007, 03:46 AM
  2. Replies: 11
    Last Post: 03-24-2006, 11:26 AM
  3. hex dump
    By coo_pal in forum Tech Board
    Replies: 2
    Last Post: 05-23-2003, 07:07 AM
  4. hex dump
    By stanleyw in forum C++ Programming
    Replies: 1
    Last Post: 06-11-2002, 04:57 PM