Recibo 2 bytes de una comunicación y luego necesito fusionar estos 2 valores para obtener un valor de 16 bits.
Ahora supongamos que espero recibir el número 200, entonces los dos caracteres son a y b
char a=0x00; char b=0xc8; int cw = (a << 8) | b ; printf("cw= %d\n",cw);Al fusionar, la variable cw se convierte en -56 en lugar de 200
Si cambio el carácter por un carácter sin firmar, obtuve el valor correcto 200 ¿Cómo puedo solucionarlo? espero recibir números positivos y negativos y por supuesto el número 200
El estándar C esencialmente no proporciona ninguna forma de cambiar un bit 1 dentro o fuera de la posición del signo (los únicos casos definidos para << son para valores no negativos que no se desbordan) y no hay una forma definitiva de convertir un valor sin signo en negativo value (las conversiones de valores fuera de rango a tipos enteros con signo están definidas por la implementación).
Así que no deberíamos usar un turno. Sin embargo, la multiplicación de valores negativos por supuesto está definida, por lo que podemos usar:
int8_t a; uint8_t b; // Put code here to receive a and b by some method. uint16_t cw = a*256 + b;Si debe reconstruir el entero con signo a partir de tipos sin signo, entonces una opción es probar el bit de signo y aplicar el complemento a dos manualmente:
unsigned char a, b; // Put code here to receive a and b by some method. int cw = (a & 0x7f) << 8 | b; // Assemble the low 15 bits. if (a & 0x80) cw += -128*256; // If sign bit is set, adjust.También puede copiar los bits en:
unsigned char a, b; // Put code here to receive a and b by some method. int16_t cw; memcpy(&cw, (uint16_t []) { (uint16_t) a << 8 | b }, sizeof cw);(Lo anterior supone que su entero de 16 bits usa complemento a dos).
Valor de 16 bits.
Simplemente use el tipo adecuado.
unsigned char a = 0x00; unsigned char b = 0xc8; int16_t cw = ((unsigned int)a << 8) | b;El único cambio que debe hacer es definir el byte menos significativo sin firmar:
char a; unsigned char b; ... // receive a and b from your communication int cw = (a << 8) | b; printf("cw = %d\n", cw); La expresión aritmética/lógica debería funcionar, pero puede que no sea trivial explicar por qué no se desborda, porque implica la promoción de char o unsigned char a int (que, supongo, es de 16 bits en su sistema).
Si desea que su código sea portátil (es decir, que no asuma un int de 16 bits o cualquier otra propiedad de su plataforma específica), use números enteros con un tamaño definido y realice una conversión explícita.
int8_t a; uint8_t b; ... // receive a and b from your communication int16_t cw = (int16_t)((int16_t)a << 8) | (int16_t)b; printf("cw = %d\n", (int)cw);Pero este código es menos legible, por lo que no estoy seguro de que ser más portátil tenga alguna ventaja aquí.