Home AMX User Forum AMX Technical Discussion
Options

how to convert a hexadecimal array to its integer equivalent

Hi!

I know i must be missing something stupid, but i can´t figure out how to convert a string with hex data to an integer.

I have this:
char acMessage[2]
integer nAux

acMessage = "$03,$02"
and i need nAux to have the decimal format of the hexadecimal number "$03,$02"

The "hextoi" function does not help because it uses a string parameter like

nAux = hextoi('0302')

But i have no way to convert the hexadecimal representation in acMessage to its string equivalent... or have i?


Ideas?
Thanx!

Comments

  • Options
    JasonSJasonS Posts: 229
    It is already a numerical value, all you have to do is bit shift the MSB (Most significant byte) and bitwise OR with the LSB. Take a look at RAW_BE and RAW_LE commands, I don't remember which direction they go. I can post code to do it when I get to work, but you can also search the forums in the mean time, I know this has been discussed before.
  • Options
    ericmedleyericmedley Posts: 4,177
    It's interesting how beguiling how Netlinx (and other development environments or that matter) handle data types can be.

    In my little brain I always try to think that they are always binary numbers. The conversion to decimal, octal, hex, ASCII etc.. Is just a convenience for us mere mortals to read more easily. keeping that in mind at all times seems to keep me from being confused by the conversions.
  • Options
    JasonSJasonS Posts: 229
    So RAW_BE and RAW_LE go the wrong way. Here is some code, assuming MSB first.
    CHAR acMessage[2]
    INTEGER nAux
    
    nAux = ((acMessage[1] << 8) | acMessage[2])
    
    
  • Options
    a_riot42a_riot42 Posts: 1,624
    MorgoZ wrote: »
    I know i must be missing something stupid, but i can´t figure out how to convert a string with hex data to an integer.

    No you are not missing something stupid, its not trivial and can get really weird if the hex numbers get larger than an integer or long. If you know how many hex characters there are, and it never changes then there are some strategies you can use. In C there is the strtoul function but Netlinx has no equivalent that I am aware of. This is some open source code for strtoul that you might be able to convert for your usage:
    strtoul.c   [plain text]
    
    /* 
     * strtoul.c --
     *
     *	Source code for the "strtoul" library procedure.
     *
     * Copyright (c) 1988 The Regents of the University of California.
     * Copyright (c) 1994 Sun Microsystems, Inc.
     *
     * See the file "license.terms" for information on usage and redistribution
     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
     *
     * RCS: @(#) $Id: strtoul.c,v 1.1.1.3 2003/03/06 00:09:04 landonf Exp $
     */
    
    #include "tclInt.h"
    #include "tclPort.h"
    
    /*
     * The table below is used to convert from ASCII digits to a
     * numerical equivalent.  It maps from '0' through 'z' to integers
     * (100 for non-digit characters).
     */
    
    static char cvtIn[] = {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9,		/* '0' - '9' */
        100, 100, 100, 100, 100, 100, 100,		/* punctuation */
        10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'A' - 'Z' */
        20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
        30, 31, 32, 33, 34, 35,
        100, 100, 100, 100, 100, 100,		/* punctuation */
        10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'a' - 'z' */
        20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
        30, 31, 32, 33, 34, 35};
    
    /*
     *----------------------------------------------------------------------
     *
     * strtoul --
     *
     *	Convert an ASCII string into an integer.
     *
     * Results:
     *	The return value is the integer equivalent of string.  If endPtr
     *	is non-NULL, then *endPtr is filled in with the character
     *	after the last one that was part of the integer.  If string
     *	doesn't contain a valid integer value, then zero is returned
     *	and *endPtr is set to string.
     *
     * Side effects:
     *	None.
     *
     *----------------------------------------------------------------------
     */
    
    unsigned long int
    strtoul(string, endPtr, base)
        CONST char *string;		/* String of ASCII digits, possibly
    				 * preceded by white space.  For bases
    				 * greater than 10, either lower- or
    				 * upper-case digits may be used.
    				 */
        char **endPtr;		/* Where to store address of terminating
    				 * character, or NULL. */
        int base;			/* Base for conversion.  Must be less
    				 * than 37.  If 0, then the base is chosen
    				 * from the leading characters of string:
    				 * "0x" means hex, "0" means octal, anything
    				 * else means decimal.
    				 */
    {
        register CONST char *p;
        register unsigned long int result = 0;
        register unsigned digit;
        int anyDigits = 0;
        int negative=0;
        int overflow=0;
    
        /*
         * Skip any leading blanks.
         */
    
        p = string;
        while (isspace(UCHAR(*p))) {
    	p += 1;
        }
        if (*p == '-') {
            negative = 1;
            p += 1;
        } else {
            if (*p == '+') {
                p += 1;
            }
        }
    
        /*
         * If no base was provided, pick one from the leading characters
         * of the string.
         */
        
        if (base == 0)
        {
    	if (*p == '0') {
    	    p += 1;
    	    if ((*p == 'x') || (*p == 'X')) {
    		p += 1;
    		base = 16;
    	    } else {
    
    		/*
    		 * Must set anyDigits here, otherwise "0" produces a
    		 * "no digits" error.
    		 */
    
    		anyDigits = 1;
    		base = 8;
    	    }
    	}
    	else base = 10;
        } else if (base == 16) {
    
    	/*
    	 * Skip a leading "0x" from hex numbers.
    	 */
    
    	if ((p[0] == '0') && ((p[1] == 'x') || (p[1] == 'X'))) {
    	    p += 2;
    	}
        }
    
        /*
         * Sorry this code is so messy, but speed seems important.  Do
         * different things for base 8, 10, 16, and other.
         */
    
        if (base == 8) {
    	unsigned long maxres = ULONG_MAX >> 3;
    	for ( ; ; p += 1) {
    	    digit = *p - '0';
    	    if (digit > 7) {
    		break;
    	    }
    	    if (result > maxres) { overflow = 1; }
    	    result = (result << 3);
    	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
    	    result += digit;
    	    anyDigits = 1;
    	}
        } else if (base == 10) {
    	unsigned long maxres = ULONG_MAX / 10;
    	for ( ; ; p += 1) {
    	    digit = *p - '0';
    	    if (digit > 9) {
    		break;
    	    }
    	    if (result > maxres) { overflow = 1; }
    	    result *= 10;
    	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
    	    result += digit;
    	    anyDigits = 1;
    	}
        } else if (base == 16) {
    	unsigned long maxres = ULONG_MAX >> 4;
    	for ( ; ; p += 1) {
    	    digit = *p - '0';
    	    if (digit > ('z' - '0')) {
    		break;
    	    }
    	    digit = cvtIn[digit];
    	    if (digit > 15) {
    		break;
    	    }
    	    if (result > maxres) { overflow = 1; }
    	    result = (result << 4);
    	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
    	    result += digit;
    	    anyDigits = 1;
    	}
        } else if ( base >= 2 && base <= 36 ) {
    	unsigned long maxres = ULONG_MAX / base;
    	for ( ; ; p += 1) {
    	    digit = *p - '0';
    	    if (digit > ('z' - '0')) {
    		break;
    	    }
    	    digit = cvtIn[digit];
    	    if (digit >= ( (unsigned) base )) {
    		break;
    	    }
    	    if (result > maxres) { overflow = 1; }
    	    result *= base;
    	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
    	    result += digit;
    	    anyDigits = 1;
    	}
        }
    
        /*
         * See if there were any digits at all.
         */
    
        if (!anyDigits) {
    	p = string;
        }
    
        if (endPtr != 0) {
    	/* unsafe, but required by the strtoul prototype */
    	*endPtr = (char *) p;
        }
    
        if (overflow) {
    	errno = ERANGE;
    	return ULONG_MAX;
        } 
        if (negative) {
    	return -result;
        }
        return result;
    }
    
    
    
  • Options
    DHawthorneDHawthorne Posts: 4,584
    Your example shows two numbers in an array. What do you want, another array with the conversions of each element, or a single number built from that array? You are mixing up concepts and getting two different answers based on which one the person responding thinks you are trying to do. But at one point you say you want an integer (in which case you have to do something like a_riot42 and JasonS suggest), and at another you say you want a string ... in which case you do nothing. What Eric says applies in that case, the compiler converts it automatically, and what you wrote down is just that, a way of writing it for your own understanding. "$03,$02" is exactly the same in NetLinx as "3,2" (no conversion in that case since the numbers are less than 10, a better example might be "$0D,$0A" = "13,10"). No matter what notation you use, it's all the same binary data to the compiler.
Sign In or Register to comment.