Thread: dump array into file in "hex format"

  1. #1
    Registered User
    Join Date
    Jul 2008
    Posts
    11

    dump array into file in "hex format"

    Hi, on my job we need to dump the content of an array ( for debug purpose ). As i'm not a very experienced programmer, i tried to code something generic ( Yes i read it here: write generic code )

    This is what i have so far:
    Code:
    /*
     *  Dump content of array into file, by A.lam
     */
    #include <stdlib.h>
    #include <stdio.h>
    int PrintArray(char *filename, void *array, int arraySize, int elementSize);
    
    int main()
    {
          int array[9]= { 0x10, 0xff, 0xaa, 0x11, 0x33, 0x55, 0x77, 0x22, 0x33 };
          int i = 0;
    
          PrintArray("c:\\log3.txt", array, sizeof(array), sizeof(int));
    
          system("PAUSE");
          return 0;
    }
    
    
    int PrintArray(char *filename, void *array, int arraySize, int elementSize)
    {
          FILE *fp;
          int i=0;
          if(!(fp = fopen(filename, "w")))
              //oops, we could not open a file for writing, exiting
              return(-1);
    
          //printout the entire array in hex notation
          fprintf(fp,"\n--------- begin printout array --------------\n");
          for(i=0; i <  arraySize/elementSize; i++ )  {
              fprintf(fp, "0X%X ", ((int*)array)[i]);
              /// WHAT IF I WANT TO PRINTOUT ANOTHER TYPE ???? ///
              //after 8 bytes we want to have a newline
              if(!((i+1)%8))
                  fprintf(fp, "\n");
          }
          fprintf(fp,"\n---------- end printout array --------------");
    
          fclose(fp);
    
          //everything went well
          return(0);
    }
    It works ok but in this example it can only printout int arrays, but what if i want to printout a char or double array.

    I want to write nice clean code . Can someone give me a hint, and tell me what you think of my code..

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    That's quite tricky. One solution would simply be to pass in a type-value (e.g. an enum that has integer, double, char, char *, and other possible output formats), and use that for a switch-statement.

    Another possibility would be to pass a function pointer that knows how to deal with the particular format expected (e.g. one function that prints double, another that prints int, another that prints char *, etc).

    You could of course implement a hybrid of the two - you have a wrapper function that calls the actual debug output code, and provides it with the relevant function pointer.

    If you make the "print table using function pointer" a public function, then you could also have individual modules add their own output function, so that a module that uses a special structure (say doing complex math, and has a struct with the real and imaginary parts) can implement it's own output function (and in this example output a table of (2.0, 10.5i) as the result).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    To expand on matsp's great suggestion, I would add a string to the call that prints out the name of the array (or other structure) you are dumping. Since you aren't going for a memory dump, but more of a specialized "what is the contents" approach, naming the areas would be a good idea.

    Along these same lines, unless you actually need the hex representation of integers, why not just print the integer value in human readable form? Do this, your specialized routines for your different arrays/structures, etc., gives you a consistent look and feel to the output data (by this I mean, you don't have to concern yourself with endianness or internal representations of data, like floats and doubles).

    I've written dumping routines that give values in both formats (hex and decimal). Works quite well for the lazy diagnostician in me.
    Mainframe assembler programmer by trade. C coder when I can.

  4. #4
    Registered User
    Join Date
    Jul 2008
    Posts
    11
    Thx for the suggestions. I'm going to use a switch construction. And i'll send the type of array in the function call. But i'm also interested how to dump the memory in an file, can you post a code snippet ?.

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Just use your current code - and give it the address of a memory location and the size you want to dump.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Quote Originally Posted by pic-o-matic View Post
    But i'm also interested how to dump the memory in an file, can you post a code snippet ?.
    Here's one way.
    Code:
    #include <stdio.h>
    #include <string.h> 
    #include <time.h> 
    #include <unistd.h>     // getcwd() ; 
    #include <sys/param.h>  // maxplathlen 
    
    #define PLACEHOLDER  '.' 
    #define FENCE "*" 
    #define OUTFILE "/Users/me/dumpdata.txt" 
    #define HEXCHARS "0123456789ABCDEF"  
    #define INFILE "/SomeFile" 
    
    
    void print_line(char *, char *, char *, FILE * ) ;  // Function prototype 
    
    
    int main (int argc, const char * argv[]) {
    	unsigned int byte ; 
    	int i, j ; 
    	char infile[MAXPATHLEN+1] ;        // Used for building the input file name 
    	char outfile[MAXPATHLEN+1] ; 
    	char outLine[6+2+(8*8)+8+1] ; // a 6-byte offset, 2 blanks, 8*8 data fields with 8 embeded blanks & 1 null term field.  
    	char workBuff[8] ;        // Temp work area 
    	char eyeCatcher[70] ;     // I need 35 bytes, but I might need escape sequences. 
    	char *outPtr ;            // Pointer into the output line 
    	char *eyePtr ;            // Pointer into eyecatcher 
    	char *timePtr ; 
    	time_t rightNow ; 
    	struct tm *tm_time ; 
    	FILE *inData, *outData ; 
    	
    	for (i=0 ;  i < argc ; ++i)  printf("argv[%d] = %s\n", i, argv[i]) ; 
    	
    	// Make sure the input file name buffer is plenty big.
    	/*
    	if (strlen(argv[0]) + strlen(argv[1]) > sizeof infile-1) { 
    		printf("Work buffer too small.  Exiting") ; 
    		return 3 ; 
    	} 
    	*/ 
    	
    	// argv[0] is the full path to the executing directory.  Parse it to back up to the last forward slash, then 
    	// append argv[1] to it to make the full path name of the input file.
    	//strcpy(infile, argv[0]) ; 
    	//strcpy(strrchr(infile,'/')+1,argv[1]) ; 
    
    	//if (argc < 2) { 
    	//	printf("\nPlease supply the input file name to be dumped as the first parm.\n") ; 
    	//	printf("Supply the output file name (the 'dump') as the second parm.\n\n") ; 
    	//	return 2 ; 
    	//} 
    
    	strcpy(infile,INFILE)  ; 
    	
    	// Print the infile area with the current working directory path. 
    //	getcwd(infile, sizeof infile) ; 
    //	if (strrchr(infile,'/') != &infile[strlen(infile)-1]) strcat(infile,"/") ; // add an ending slash if not one 
    //	strcat(infile, argv[1]) ;  // append the passed file name 
    	
    	printf("Built input file name = %s\n", infile) ; 
    
    //	inData  = fopen(argv[1], "rb") ; 
    	inData  = fopen(infile, "rb") ; 
    	if (!inData) { 
    		printf("Cannot open input file.\n") ; 
    		return 2 ; 
    	} 
    	
    	// Allow user to set the output file name. 
    	if (argc >= 3) strcpy(outfile,argv[2]) ;  // user pass outfile name. 
    	else strcpy(outfile,OUTFILE) ; // assume default outfile name. 
    	printf("Built output file name = %s\n", outfile) ; 
    	outData = fopen(outfile,"w") ; 
    	if (!outData) { 
    		printf("Cannot open output file.\n") ; 
    		return 1 ; 
    	}
    	
    	// Print out a heading. 
    	time(&rightNow) ; 
    	tm_time = localtime(&rightNow) ; 
    	timePtr = asctime(tm_time) ; 
    	fprintf(outData, "(c) Copyright 2007 Todd Burch.  All Rights Reserved.\n") ; 
    	fprintf(outData, "\nDump of %s taken on %s\n" , infile, timePtr ) ; 
    	fprintf(outData, "OFFSET:\n" ) ; 
    	
    	for ( i=0 ; ; ++i ) {   // Infinite loop until END OF FILE
    		
    		// Read a byte.  Exit if we hit end of file 
    		byte = fgetc(inData)  ; 
    		if (byte == EOF) break ; 
    		if (i==100000) break ; 
    		
    		// print the dump offset if a new line. 
    		if (i%32==0) {
    			
    			for (j = 0, outPtr = outLine    ; j < (sizeof outLine)-1 ; *outPtr++ = ' ',  ++j ) ;  // reset outLine 
    			*outPtr = (char)NULL ;                                                                      // null term it 
    			for (j = 0, eyePtr = eyeCatcher ; j < sizeof eyeCatcher  ; *eyePtr++ = (char)NULL , ++j ) ; // reset eyecather 
    			eyePtr = eyeCatcher ; // reset pointer again 
    			outPtr = outLine ;   // set up the outline pointer again 
    			
    			sprintf(workBuff, "%06X  ", i ) ;   // Add an "000000" style offset to the front of the line. 
    			memcpy(outPtr, workBuff, 8) ; 
    			outPtr += 8 ; // bump pointer 
    		}
    		
    		// Convert byte to hex and add to output line. 
    		*outPtr++ = HEXCHARS[ byte / 16 ] ; 
    		*outPtr++ = HEXCHARS[ byte % 16 ] ;
    		
    		// Set up the eyecatcher.  
    		if (isprint(byte)) { 
    			*eyePtr++ = byte ; 
    			if (byte == '%') *eyePtr++ = byte ;   // Double up if this is an escape character  
    		} 
    		else *eyePtr++ = PLACEHOLDER  ;           // print default non-printable character. 
    
    		// Print and then reset the eyecatcher if at the end of the line. 
    		if ( (i+1) % 32 == 0) print_line(eyePtr, outLine, eyeCatcher, outData ) ; 
    		// If not at the end of the line, add some visual breaks in the hex data. 
    		else if ( (i+1) % 16 == 0) {   // 2 spaces in the middle 
    			*outPtr++ = ' ' ;  
    			*outPtr++ = ' ' ;  
    		}
    		else if ( (i+1) % 4 == 0) *outPtr++ = ' ' ;  // space every word 
    	} 
    	
    	// We hit EOF.  Process any remaining data. 
    	if (!( i%32 ) == 0) print_line(eyePtr, outLine, eyeCatcher, outData ) ; 
    	
    	fclose(outData) ; 
    	fclose(inData) ; 
    	return 0 ; 
    }
    
    
    void print_line(char *eyePtr, char *outLine, char *eyeCatcher, FILE *outData) { 
    		// Build Eyecatcher 
    		*eyePtr = (char)NULL ;     // null term it early 
    		strcat(outLine, "   ") ;
    		strcat(outLine, FENCE ) ;  
    		strcat(outLine, eyeCatcher) ;  // append eyecatcher 
    		strcat(outLine, FENCE ) ;  
    		strcat(outLine, "\n");         // complete eyecatcher, line return 
    		fprintf(outData,outLine) ;     // write it out
    	return ; 
    }
    Mainframe assembler programmer by trade. C coder when I can.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File transfer- the file sometimes not full transferred
    By shu_fei86 in forum C# Programming
    Replies: 13
    Last Post: 03-13-2009, 12:44 PM
  2. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. Encryption program
    By zeiffelz in forum C Programming
    Replies: 1
    Last Post: 06-15-2005, 03:39 AM