2011-03-08 15 views
7

n.b. Sé que esta pregunta se ha formulado sobre StackOverflow anteriormente en una variedad de formas y circunstancias diferentes, pero la búsqueda de la respuesta que busco no ayuda en mi caso específico. Entonces, aunque inicialmente parece un duplicado de una pregunta como How can I convert an integer to a hexadecimal string in C?, las respuestas dadas son precisas, pero no útiles para mí.¿Cómo convertir manualmente el valor decimal a cadena hexadecimal en C?

Mi pregunta es cómo convertir manualmente un entero decimal en una cadena hexadecimal. Sé que hay algunos trucos de ritmo con stdlib.hy printf, pero esta es una tarea de la universidad, y tengo que hacerlo manualmente (órdenes del profesor). Sin embargo, se nos permite buscar ayuda.

Usando el buen viejo "se divide por 16 y convirtiendo el resto a hexadecimal y revertir los valores" método para obtener la cadena hexadecimal, pero tiene que haber un gran error en mi código, ya que no me está dando la espalda, por ejemplo "BC" para el valor decimal "188".

Se supone que el algoritmo NUNCA necesitará encontrar valores hexadecimales para decimales mayores que 256 (o FF). Si bien el paso de los parámetros puede no ser óptimo o deseable, es lo que nos han dicho que usemos (aunque puedo modificar la función getHexValue, ya que yo mismo escribí esa).

Esto es lo que tengo hasta ahora:

/* Function to get the hex character for a decimal (value) between 
* 0 and 16. Invalid values are returned as -1. 
*/ 
char getHexValue(int value) 
{ 
    if (value < 0) return -1; 
    if (value > 16) return -1; 
    if (value <= 9) return (char)value; 
    value -= 10; 
    return (char)('A' + value); 
} 


/* Function asciiToHexadecimal() converts a given character (inputChar) to 
* its hexadecimal (base 16) equivalent, stored as a string of 
* hexadecimal digits in hexString. This function will be used in menu 
* option 1. 
*/ 
void asciiToHexadecimal(char inputChar, char *hexString) 
{ 
    int i = 0; 
    int remainders[2]; 
    int result = (int)inputChar; 
    while (result) { 
     remainders[i++] = result % 16; 
     result /= (int)16; 
    } 
    int j = 0; 
    for (i = 2; i >= 0; --i) { 
     char c = getHexValue(remainders[i]); 
     *(hexString + (j++)) = c; 
    } 
} 

El char *hexString es el puntero a la cadena de caracteres que necesito para dar salida a la pantalla (con el tiempo). El parámetro char inputChar que necesito convertir a hexadecimal (por lo que nunca es necesario convertir valores por encima de 256).

Si hay una mejor manera de hacer esto, que todavía utiliza la función void asciiToHexadecimal(char inputChar, char *hexString), yo soy todo oídos, aparte de eso, mi depuración parece indicar los valores están bien, pero la salida sale como \377 en lugar de la representación alfanumérica hexadecimal esperada.

Lo siento si hay alguna terminología u otros problemas con la pregunta en sí (o con el código), todavía soy muy nuevo en el mundo de C.

Actualización: Se me acaba de ocurrir que podría ser relevante publicar la forma en que estoy mostrando el valor en caso de que sea la impresión, y no la conversión que es defectuosa. Aquí está:

char* binaryString = (char*) malloc(8); 
char* hexString = (char*) malloc(2); 
asciiToBinary(*(asciiString + i), binaryString); 
asciiToHexadecimal(*(asciiString + i), hexString); 
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString); 

(Todo en este código funciona tijeretazo a cielo excepto por hexString)

+9

+1 para una pregunta bien presentada y para hacer un gran esfuerzo con la tarea antes de buscar ayuda. Desearía que más preguntas sobre 'deberes' fueran de una calidad similar. –

+2

.. y excelente pensamiento sobre el _output_, también! – sarnold

+0

"la salida sale como \ 377" - '\ 377' es' (char) -1'. Su rutina 'getHexValue' devuelve un int negativo como un código de error, pero se escribe para devolver un' char', y luego nunca se comprueba el código de error, eso es doblemente malo. –

Respuesta

2
char getHexValue(int value) 
{ 
    if (value < 0) return -1; 
    if (value > 16) return -1; 
    if (value <= 9) return (char)value; 
    value -= 10; 
    return (char)('A' + value); 
} 

Es posible que desee imprimir los caracteres que recibe de llamar a esta rutina para cada valor que le interesa. :) (printf(3) formato %c.)

Cuando llama al getHexValue() con un número entre 0 y 9, devuelve un número entre 0 y 9, en el rango de caracteres de control ASCII. Cuando llama al getHexValue() con un número entre 10 y 15, devuelve un número entre 65 y 75, en el rango de letras ASCII.

¿El sermón? Unit testing puede ahorrarle horas de tiempo si escribe las pruebas aproximadamente al mismo tiempo que escribe el código.

A algunas personas les encanta escribir las pruebas primero. Si bien nunca he tenido la disciplina para seguir este enfoque por mucho tiempo, sabiendo que tiene para escribir pruebas, lo forzaré a escribir código que es más fácil para probar. Y el código que es más fácil de probar es less coupled (o 'más desacoplado'), ¡lo que generalmente genera menos errores!

Escribir pruebas temprano y con frecuencia. :)

actualización: Después de que haya incluido su código de salida, tenía que comentar en este también :)

char* binaryString = (char*) malloc(8); 
char* hexString = (char*) malloc(2); 
asciiToBinary(*(asciiString + i), binaryString); 
asciiToHexadecimal(*(asciiString + i), hexString); 
printf("%6c%13s%9s\n", *(asciiString + i), binaryString, hexString); 

hexString se ha asignado un byte demasiado pequeño para ser un C- cadena: olvidó dejar espacio para el carácter ASCII NUL '\0'. Si estaba imprimiendo hexString mediante el especificador de formato %c, o construyendo una cadena más grande usando memcpy(3), podría estar bien, pero su llamada a printf() está tratando hexString como una cadena.

En general, cuando se ve una llamada

char *foo = malloc(N); 

, tenga miedo - el lenguaje C es

char *foo = malloc(N+1); 

Eso +1 es su señal a otros (y usted mismo, en dos meses) que has dejado espacio para el NUL. Si oculta ese +1 en otro cálculo, está perdiendo la oportunidad de memorizar un patrón que puede detectar estos errores cada vez que lee el código. (Honestamente, encontré uno de estos a través de este patrón exacto en SO solo hace dos días. :)

+0

Esto es genial, y gracias por tomarse el tiempo para ayudarme a encontrar el error. Creo que veo a lo que te refieres y haré los cambios apropiados. En cuanto a las pruebas unitarias, soy un gran admirador de las pruebas unitarias en C# y Ruby/Rails de donde es la mayor parte de mi experiencia, pero no tengo idea de cómo ajustar un marco de prueba alrededor de este código C, cuya base nos fue suministrada de nuestro profesor, y le dijeron que no cambie. Por último, sobre la idea de la idea 'malloc (N + 1);'; Me encanta esto. No lo había considerado antes, y tiene toda la razón de que es más fácil de leer. ¡Gracias! :) – Ash

+0

WOOT! Lo puse en funcionamiento, gracias por tus consejos (¡Ajá, perdona el juego de palabras!) - También descubrí otro error con la línea 'for (i = 2; i> = 0; --i) {' que DEBERÍA ser 'for (i = 1; i> = 0; --i) {':) Pero, una vez más, ¡lo he probado y funciona estupendamente! Gracias. – Ash

+0

@ Ash, ¡ja! Perdón por haberme perdido ese.Aún así, felicidades. :) – sarnold

0

Estás muy cerca - hacer las siguientes dos cambios pequeños y se va a trabajar lo suficientemente bien como para que usted pueda acabar con él:

(1) el cambio:

if (value <= 9) return (char)value; 

a:

if (value <= 9) return '0' + value; 

(necesita convertir el valor 0,9 a un carácter, no solo echarlo).

(2) cambio:

void asciiToHexadecimal(char inputChar, char *hexString) 

a:

void asciiToHexadecimal(unsigned char inputChar, char *hexString) 

(inputChar estaba siendo tratado como firmado, que dio resultados no deseados con %).

Un par de consejos:

  • tienen getHexValue volver '?' en lugar de -1 de entrada no válida (hacer más fácil la depuración)

  • redactar un instrumento de prueba para la depuración, por ejemplo,

    int main(void) 
    { 
        char hexString[256]; 
    
        asciiToHexadecimal(166, hexString); 
    
        printf("hexString = %s = %#x %#x %#x ...\n", hexString, hexString[0], hexString[1], hexString[2]); 
    
        return 0; 
    } 
    
+0

Gracias por su respuesta, se agradece, pero no puedo cambiar la firma de asciiToHexadecimal. :) – Ash

1

Es el destino puramente hexadecimal, o la función debe ser parametrizable. Si está restringido a hexadecimal, ¿por qué no explotar el hecho de que un solo dígito hexadecimal codifica exactamente cuatro bits?

Esta es la forma en que lo haría:

#include <stdlib.h> 

#include <limits.h> /* implementation's CHAR_BIT */ 

#define INT_HEXSTRING_LENGTH (sizeof(int)*CHAR_BIT/4) 
/* We define this helper array in case we run on an architecture 
    with some crude, discontinous charset -- THEY EXIST! */ 
static char const HEXDIGITS[0x10] = 
    {'0', '1', '2', '3', '4', '5', '6', '7', 
    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 
void int_to_hexstring(int value, char result[INT_HEXSTRING_LENGTH+1]) 
{ 
    int i; 
    result[INT_HEXSTRING_LENGTH] = '\0'; 

    for(i=INT_HEXSTRING_LENGTH-1; value; i--, value >>= 4) { 
     int d = value & 0xf; 
     result[i] = HEXDIGITS[d]; 
    } 

    for(;i>=0;i--){ result[i] = '0'; } 
} 
int main(int argc, char *argv[]) 
{ 
    char buf[INT_HEXSTRING_LENGTH+1]; 

    if(argc < 2) 
     return -1; 

    int_to_hexstring(atoi(argv[1]), buf); 
    puts(buf); 
    putchar('\n'); 

    return 0; 
} 
+0

Elegante y apropiado. –

1

hice un librairy para hacer la conversión hexadecimal/decimal sin el uso de stdio.h. Muy fácil de usar:

char* dechex (int dec); 

Esto utilizará calloc() a devolver un puntero a una cadena hexadecimal, de esta manera se optimiza la cantidad de memoria utilizada, por lo que no se olvide de utilizar free()

Aquí el enlace en github: https://github.com/kevmuret/libhex/

0
#include<stdio.h> 

char* inttohex(int); 
main() 
{ 
    int i; 
    char *c; 
    printf("Enter the no.\n"); 
    scanf("%d",&i); 
    c=inttohex(i); 
    printf("c=%s",c); 
} 

char* inttohex(int i) 
{ 
    int l1,l2,j=0,n; 
    static char a[100],t; 

    while(i!=0) 
    { 
    l1=i%16; 
    if(l1>10) 
    { 
     a[j]=l1-10+'A'; 
    } 

    else 
     sprintf(a+j,"%d",l1); 

    i=i/16; 
    j++; 
    } 
    n=strlen(a); 
    for(i=0;i<n/2;i++) 
    { 
     t=a[i]; 
     a[i]=a[n-i-1]; 
     a[n-i-1]=t; 
    } 

    //printf("string:%s",a); 
    return a; 
    // 
} 
0

en complemento de las otras buenas respuestas ....

Si el número represe nted por estas cadenas de caracteres hexadecimales o decimales son enormes (p. cientos de dígitos), no caben en un long long (o el tipo integral más grande que proporcione su implementación C). Entonces necesitarás bignums. Sugeriría que no codifique su propia implementación (es complicado hacer una eficiente), pero use una existente como GMPlib

Cuestiones relacionadas