Tengo un número int sin firmar (2 bytes) y quiero convertirlo al tipo de caracteres sin firmar. De mi búsqueda, encuentro que la mayoría de las personas recomiendan hacer lo siguiente:
unsigned int x;
...
unsigned char ch = (unsigned char)x;
¿Es el enfoque correcto? Pregunto porque el carácter sin firmar es de 1 byte y pasamos de datos de 2 bytes a 1 byte.
Para evitar la pérdida de datos, quiero crear una matriz de caracteres sin firmar[] y guarde los bytes individuales en la matriz. Estoy atascado en lo siguiente:
unsigned char ch[2];
unsigned int num = 272;
for(i=0; i<2; i++){
// how should the individual bytes from num be saved in ch[0] and ch[1] ??
}
También, ¿Cómo convertiríamos el carácter sin firmar?[2] volver a int sin firmar.
Muchas gracias.
Puedes usar memcpy
en ese caso:
memcpy(ch, (char*)&num, 2); /* although sizeof(int) would be better */
Además, ¿cómo se convertiría el carácter sin firmar?[2] volver a int sin firmar.
De la misma manera, simplemente invierta los argumentos de memcpy.
Qué tal si:
ch[0] = num & 0xFF;
ch[1] = (num >> 8) & 0xFF;
La operación inversa se deja como ejercicio.
¿Qué tal usar una unión?
union {
unsigned int num;
unsigned char ch[2];
} theValue;
theValue.num = 272;
printf("The two bytes: %d and %d\n", theValue.ch[0], theValue.ch[1]);
Realmente depende de tu objetivo: ¿por qué quieres convertir esto en un unsigned char
? Dependiendo de la respuesta a eso, hay algunas maneras diferentes de hacer esto:
-
Truncar: Esto es lo que se recomendó. Si solo está tratando de introducir datos en una función que requiere un
unsigned char
simplemente lanzauchar ch = (uchar)x
(pero, por supuesto, tenga cuidado con lo que sucede si su int es demasiado grande). -
endiano específico: use esto cuando su destino requiera un formato específico. Por lo general, al código de red le gusta todo lo que se convierte en matrices de caracteres big endian:
int n = sizeof x; for(int y=0; n-->0; y++) ch[y] = (x>>(n*8))&0xff;
voluntad hace eso.
-
Máquina endiana. Úselo cuando no haya un requisito de endianness y los datos solo se produzcan en una máquina. El orden de la matriz cambiará en diferentes arquitecturas. La gente suele encargarse de esto con
union
s:union {int x; char ch[sizeof (int)];} u; u.x = 0xf00 //use u.ch
con
memcpy
:uchar ch[sizeof(int)]; memcpy(&ch, &x, sizeof x);
o con la conversión simple siempre peligrosa (que es un comportamiento indefinido y falla en numerosos sistemas):
char *ch = (unsigned char *)&x;
Agente_L
Por supuesto, una matriz de caracteres lo suficientemente grande como para contener un valor mayor tiene que ser exactamente tan grande como este valor en sí. Entonces, simplemente puede pretender que este valor más grande ya es una matriz de caracteres:
unsigned int x = 12345678;//well, it should be just 1234.
unsigned char* pChars;
pChars = (unsigned char*) &x;
pChars[0];//one byte is here
pChars[1];//another byte here
(Una vez que comprenda lo que está sucediendo, puede hacerlo sin ninguna variable, todo solo con casting)
-
Si
12345678
encajaunsigned int
ysizeof(unsigned int) == 2
despuésCHAR_BIT
es más grande de lo normal 😉–Steve Jessop
25 de abril de 2012 a las 16:39
-
¡Culpo a la sociedad de 32 bits por consentirme!
– Agente_L
25 de abril de 2012 a las 16:44
Solo necesita extraer esos bytes usando bitwise & operator
. OxFF
es una máscara hexadecimal para extraer un byte. Mire varias operaciones de bits aquí: http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/
Un ejemplo de programa es el siguiente:
#include <stdio.h>
int main()
{
unsigned int i = 0x1122;
unsigned char c[2];
c[0] = i & 0xFF;
c[1] = (i>>8) & 0xFF;
printf("c[0] = %x \n", c[0]);
printf("c[1] = %x \n", c[1]);
printf("i = %x \n", i);
return 0;
}
Producción:
$ gcc 1.c
$ ./a.out
c[0] = 22
c[1] = 11
i = 1122
$
-
Si
12345678
encajaunsigned int
ysizeof(unsigned int) == 2
despuésCHAR_BIT
es más grande de lo normal 😉–Steve Jessop
25 de abril de 2012 a las 16:39
-
¡Culpo a la sociedad de 32 bits por consentirme!
– Agente_L
25 de abril de 2012 a las 16:44
jonathask
Apoyando la sugerencia de @abelenky, usando un union
sería una forma más a prueba de fallas de hacer esto.
union unsigned_number {
unsigned int value; // An int is 4 bytes long
unsigned char index[4]; // A char is 1 byte long
};
Las características de este tipo es que el compilador asignará memoria solo para el miembro más grande de nuestra estructura de datos. unsigned_number
que en este caso va a ser 4 bytes – ya que ambos miembros (valor e índice) tienen el mismo tamaño. ¿Lo habías definido como un struct
en cambio, tendríamos 8 bytes asignado en la memoria, ya que el compilador hace su asignación para todos los miembros de un struct
.
Además, y aquí es donde se resuelve su problema, los miembros de un union
estructura de datos todos comparten la misma ubicación de memorialo que significa que todos se refieren a los mismos datos; piense en eso como un enlace fijo en los sistemas GNU/Linux.
Entonces tendríamos:
union unsigned_number my_number;
// Assigning decimal value 202050300 to my_number
// which is represented as 0xC0B0AFC in hex format
my_number.value = 0xC0B0AFC; // Representation: Binary - Decimal
// Byte 3: 00001100 - 12
// Byte 2: 00001011 - 11
// Byte 1: 00001010 - 10
// Byte 0: 11111100 - 252
// Printing out my_number one byte at time
for (int i = 0; i < (sizeof(my_number.value)); i++)
{
printf("index[%d]: %u, 0x%x\n", \
i, my_number.index[i], my_number.index[i]);
}
// Printing out my_number as an unsigned integer
printf("my_number.value: %u, 0x%x", my_number.value, my_number.value);
Y la salida va a ser:
index[0]: 252, 0xfc
index[1]: 10, 0xa
index[2]: 11, 0xb
index[3]: 12, 0xc
my_number.value: 202050300, 0xc0b0afc
Y en cuanto a su pregunta final, no tendríamos que convertir de carácter sin firmar de regreso int sin firmar ya que los valores ya están ahí. Solo tienes que elegir por qué vía quieres acceder
Nota 1: Estoy usando un número entero de 4 bytes para facilitar la comprensión del concepto. Para el problema que presentaste debes usar:
union unsigned_number {
unsigned short int value; // A short int is 2 bytes long
unsigned char index[2]; // A char is 1 byte long
};
Nota 2: he asignado byte 0
a 252
para señalar la característica no firmada de nuestro index
campo. ¿Fue declarado como un signed char
tendríamos index[0]: -4, 0xfc
como salida.
posible duplicado de byte corto firmado en c ++
– Pablo R.
25 de abril de 2012 a las 16:34