You might need to use floating-point variables in some embedded software algorithms. You'll find this easy to do because all modern C compilers come with a floating-point library. However, when you're debugging a routine, you sometimes need to "peek" or "poke" a floating-point variable when all you have available is a hexadecimal interface. This scenario arises because simple debuggers or monitor programs usually don't know anything about C variable types. The software can only read or write bytes in ASCII hexadecimal.
You can get around this limitation by using a simple program on a PC to convert between ASCII hexadecimal bytes and decimal floating-point numbers. The program takes advantage of the fact that most embedded software compilers support the IEEE 754 floating-point standard, which is the same format the PC supports. You can have exceptions, though, such as DSP chips that support proprietary floating-point formats with internal hardware. In general, if the floating-point support is through a software library, the software probably uses the IEEE format.
To use the program, you type in the name of the program, followed by one or two parameters. The first parameter is always the number you want to convert. If the number contains a decimal point, the program assumes it to be a decimal number, which the routine converts and prints out as ASCII hexadecimal bytes. If the number doesn't contain a decimal point, the software assumes it to be ASCII hexadecimal and converts and prints the number out as a decimal. You must type in the proper number of hexadecimal digits (8 or 16); you can use either uppercase or lowercase.
By default, the program assumes you want 32-bit, single-precision floating-point numbers and that the hexadecimal bytes start with the least significant byte (in IEEE format, the 8 LSBs of the fraction or mantissa). You can enter a second parameter to override the defaults: D for "double" (64-bit double-precision format), R for "reverse" (most significant byte firstin IEEE format, the sign and exponent), or DR for both. You can use either uppercase or lowercase.
The following are some examples. The first line, starting with "float," is what you enter, and the information following is the program's response.
float 123.456 32-bit 123.456001 = hex 79 E9 F6 42 (LS byte first) float 123.456 DR 64-bit 123.4560000000000 = hex 40 5E DD 2F 1A 9F BE 77 (MS byte first) float 42f6e979 r hex 42 F6 E9 79 = 123.456001 (32-bit) float 1234567890abcdef d hex 12 34 56 78 90 AB CD EF = -3.598709427848316e+230 (64-bit)
Incidentally, if the result ever says "INF" (which stands for infinity), the hexadecimal value you entered is the IEEE representation of infinity. You might also get a result "NAN" (not a number), which is the IEEE way of presenting a non-numerical result, such as the result of dividing infinity by infinity.
The program compiles with Borland C++, but it should also work with other PC compilers. Make sure the compiler options specify "normal" floating-point operationsome compilers also support nonstandard floating point for faster operation.
/*************************************************************************** **************************************************************************** FLOAT.C 05-Oct-88 J. Santic Converts a hexadecimal IEEE floating point number to its numeric equivalent. The program prompts for the hexadecimal number, then displays the result. Enter just a carriage-return to exit. The program only converts single-precision numbers. Microsoft C uses the IEEE floating point format for internal C floating point variables, so the hex bytes are poked into a floating variable, then the variable is printed just like any other floating variable. **************************************************************************** ***************************************************************************/ #include <stdio.h> #include <string.h> #include "aschex.h" #define TRUE 1 #define FALSE 0 #define LINE_LENGTH 80 /* Maximum number of characters accepted */ #define FLOAT_HEX_LENGTH 8 /* how many characters in hex IEEE number */ #define HEX_ERROR -1 /* error flag from asc2bin */ char hex_string [LINE_LENGTH + 1]; /* user's entry */ char *index; /* pointer to entry character */ int byte; /* binary value of two hex characters */ unsigned char *special_ptr; /* used to poke bytes into float_value */ float float_value; /* the result, we'll print this */ int hex_counter; /* counts number of hex characters processed */ unsigned char error_flag; /* TRUE if error in hex entry */ /*------------------------------------------------------------------------*/ void main (void) { /* Display welcome message and instructions for use. */ printf ("\nFLOAT.C - This program converts single-precision IEEE\n"); printf ("floating-point numbers from hexadecimal to ASCII numeric.\n"); printf ("Enter the hexadecimal number as eight characters, MSB first.\n"); printf ("Enter just a carriage return to exit.\n\n"); /* Execute the main processing loop forever, until user wants to exit. */ while (TRUE) { /* Prompt for and get the eight-character hexadecimal number. */ printf ("Enter eight-character hexadecimal number (MSB first): "); gets (hex_string); if (strlen (hex_string) == 0) { /* Exit if carriage-return only. */ printf ("\nProgram terminated\n\n"); return; } if (strlen (hex_string) != FLOAT_HEX_LENGTH) { printf ("Error, you must enter eight characters\n"); continue; } /* Convert each pair of hex characters into a binary byte, then poke the byte into the correct position in float_value. The string is processed from MSB to LSB, but float_value is stored in memory from LSB to MSB. */ index = hex_string; /* initialize pointer to hexadecimal characters */ error_flag = FALSE; /* no error in hex entry (yet) */ /* Point at last byte of float_value. */ special_ptr = (& (unsigned char) float_value) + 3; for (hex_counter = 0; hex_counter < FLOAT_HEX_LENGTH; hex_counter += 2) { byte = asc2bin (&index); if (byte == HEX_ERROR) { printf ("Error, invalid hexadecimal character\n"); error_flag = TRUE; break; } /* Poke byte into correct position into float_value. */ *(special_ptr--) = (unsigned char) byte; } /* If there wasn't any error, print out the result. */ if (!error_flag) printf ("Decimal number: %f\n", float_value); } /* end while */ }
The following utility module and header file are referenced by the above routine:
/****************************************************************************** ******************************************************************************* ASCHEX.C August 23, 1988 John S. Santic This module provides the following ASCII hex functions: htoi - converts ASCII hex characters to binary word asc2bin - converts two ASCII hex characters to binary byte asc1bin - converts one ASCII hex character to binary nibble bin4asc - converts binary word to four ASCII hex characters bin2asc - converts binary byte to two ASCII hex characters bin1asc - converts binary nibble to one ASCII hex character nbin4asc - like bin4asc, but string is null-terminated nbin2asc - like bin2asc, but string is null-terminated nbin1asc - like bin1asc, but string is null-terminated To use this file, you must include the file ASCHEX.H in your source file and link with the file ASCHEX.OBJ. 16-Oct-90 Santic, revised for Turbo C. ******************************************************************************* ******************************************************************************/ #include "ctype.h" /* Function prototypes. */ int htoi (char *index); int asc2bin (char **index); int asc1bin (char **index); void bin4asc (unsigned int value, char **index); void bin2asc (unsigned int value, char **index); void bin1asc (unsigned int value, char **index); void nbin4asc (unsigned int value, char **index); void nbin2asc (unsigned int value, char **index); void nbin1asc (unsigned int value, char **index); /* Logical constants. */ #define TRUE 1 #define FALSE 0 /****************************** htoi **************************************** Converts ASCII hex characters to a binary word. Returns binary 0 to 0xffff. Does NOT detect overflow if ASCII hex value is greater than FFFF. Stops converting upon encountering any non-hexadecimal character. ******************************************************************************/ int htoi ( char *index) /* points to MSB ASCII hex digit */ { int value, digit; /*--------------------------------------------------------------------------*/ value = 0; while (TRUE) { if ((digit = asc1bin (&index)) == -1) return value; value = (value << 4) + digit; } } /****************************** asc2bin ************************************* Converts two ASCII hex characters to binary. Returns binary 0 to 255, or -1 if error. Pass in pointer to string pointer, updates string pointer to point at character after second ASCII hex character. ******************************************************************************/ int asc2bin ( char **index) /* points to pointer to MSB ASCII digit */ { int msb, lsb; /*--------------------------------------------------------------------------*/ if ((msb = asc1bin (index)) == -1) return -1; if ((lsb = asc1bin (index)) == -1) return -1; return (msb << 4) | lsb; } /***************************** asc1bin ************************************** Converts one ASCII hex character to binary. Returns binary 0 to 15, or -1 if error. Pass in pointer to string pointer, updates string pointer to point at character after ASCII hex character. ******************************************************************************/ int asc1bin ( char **index) /* points to pointer to ASCII digit */ { char value; /*--------------------------------------------------------------------------*/ value = toupper (**index); /* get ASCII hex digit */ (*index)++; /* bump pointer */ if (value >= '0' && value <= '9') return value - '0'; if (value >= 'A' && value <= 'F') return value - '7'; return -1; } /****************************** bin4asc ************************************* Converts a binary word into four ASCII hex characters, which are stored where the string pointer indicates, then increments the string pointer for each character. ******************************************************************************/ void bin4asc ( unsigned int value, /* binary word */ char **index) /* points to pointer to ASCII digit */ { bin2asc (value >> 8, index); bin2asc (value, index); return; } /****************************** bin2asc ************************************* Converts a binary byte into two ASCII hex characters, which are stored where the string pointer indicates, then increments the string pointer for each character. ******************************************************************************/ void bin2asc ( unsigned int value, /* binary byte (only lower eight bits are used) */ char **index) /* points to pointer to ASCII digit */ { bin1asc (value >> 4, index); bin1asc (value, index); return; } /****************************** bin1asc ************************************* Converts a binary nibble into one ASCII hex character, which is stored where the string pointer indicates, then increments the string pointer. ******************************************************************************/ void bin1asc ( unsigned int value, /* binary nibble (only lower four bits are used) */ char **index) /* points to pointer to ASCII digit */ { value &= 0xf; if (value <= 9) **index = (char) value + '0'; else **index = (char) value + '7'; (*index)++; return; } /****************************** nbin4asc ************************************ Converts a binary word into four ASCII hex characters, which are stored where the string pointer indicates, then increments the string pointer for each character. String is null-terminated. ******************************************************************************/ void nbin4asc ( unsigned int value, /* binary word */ char **index) /* points to pointer to ASCII digit */ { bin4asc (value, index); **index = '\0'; return; } /****************************** nbin2asc ************************************ Converts a binary byte into two ASCII hex characters, which are stored where the string pointer indicates, then increments the string pointer for each character. String is null-terminated. ******************************************************************************/ void nbin2asc ( unsigned int value, /* binary byte (only lower eight bits are used) */ char **index) /* points to pointer to ASCII digit */ { bin2asc (value, index); **index = '\0'; return; } /****************************** nbin1asc ************************************ Converts a binary nibble into one ASCII hex character, which is stored where the string pointer indicates, then increments the string pointer. String is null-terminated. ******************************************************************************/ void nbin1asc ( unsigned int value, /* binary nibble (only lower four bits are used) */ char **index) /* points to pointer to ASCII digit */ { bin1asc (value, index); **index = '\0'; return; } /****************************************************************************** ******************************************************************************* ASCHEX.H August 23, 1988 John S. Santic This include file contains function prototypes for the ASCII hex functions. If you use any of the ASCII hex functions, you must include this file in your source file. 16-Oct-90 Santic, modified for Turbo C. ******************************************************************************* ******************************************************************************/ int extern htoi (char *index); int extern asc2bin (char **index); int extern asc1bin (char **index); void extern bin4asc (unsigned int value, char **index); void extern bin2asc (unsigned int value, char **index); void extern bin1asc (unsigned int value, char **index); void extern nbin4asc (unsigned int value, char **index); void extern nbin2asc (unsigned int value, char **index); void extern nbin1asc (unsigned int value, char **index);
Computer Page | Home Page |