No estoy seguro de si esto es posible debido al relleno y la alineación de la estructura, pero suponiendo que se ocupe de eso alineando sus estructuras a 4/8 bytes, ¿es posible cambiar de bit en una estructura como si fuera una sola variable?
Lo que me gustaría hacer es tomar una cadena (8 bytes como máximo) y cambiarla a los bits de orden superior de una variable de 64 bits.
Like si hago esto:
#include <stdint.h> #include <string.h> void shiftstr(uint64_t* t,char* c,size_t len){ memcpy(t, c, len); //now *t==0x000000617369616b *t<<=(sizeof(uint64_t)-len)*8; //now *t==0x617369616b000000 } int main(){ uint64_t k = 0; char n[] = "kaisa"; shiftstr(&k, n,strlen(n)); return 0; } Esto funciona bien, pero ¿qué pasaría si tuviera, en lugar de un uint64_t , dos uint32_t , ya sea como variables individuales o como una estructura?
#include <stdint.h> #include <string.h> struct U64{ uint32_t x; uint32_t y; }; void shiftstrstruct(struct U64* t, char* c, size_t len){ memcpy(t, c, len); /* At this point I think x == 0x7369616b y == 0x00000061 But I could be wrong */ //but how can I perform the bit shift? //Where //x==0x0000006b //y==0x61697361 } int main(){ char n[] = "kaisa"; struct U64 m = {0}; shiftstrstruct(&m, n, strlen(n)); return 0; } Hasta la parte de memcpy , debería ser lo mismo que si lo estuviera realizando en una sola variable. Creo que los valores de x e y son correctos en tales situaciones. Pero, si ese es el caso, eso significa que los valores deben cambiarse de x hacia y .
Sé que puedo transmitir, pero ¿qué pasa si quiero lidiar con una cadena de 16 bytes que necesita cambiarse a dos variables de 64 bits, o incluso más grandes?
¿Es posible cambiar estructuras como esta? ¿Hay una mejor alternativa?
¿Es posible cambiar estructuras como esta?
No en realidad no. Incluso si los miembros x e y están en ubicaciones de memoria adyacentes, las operaciones de desplazamiento de bits en cualquiera se realizan como operaciones de enteros en las variables individuales. Por lo tanto, no puede cambiar bits "fuera" de uno y "dentro" del otro: los bits que "caen" durante el cambio se perderán.
¿Hay una mejor alternativa?
Usted mismo tendría que implementar un desplazamiento de bits de múltiples componentes, haciendo copias de los bits que de otro modo se perderían y enmascararlos de alguna manera en el resultado, después de desplazar otros bits internamente a cada variable de 'componente'. Exactamente cómo hacer esto dependería en gran medida del caso de uso.
Aquí hay una posible implementación de una función de desplazamiento a la derecha para una estructura que comprende dos miembros uint64_t (no he agregado ninguna verificación de errores para el count , y asumo que uint64_t tiene exactamente 64 bits de ancho):
#include <stdio.h> #include <stdint.h> typedef struct { uint64_t hi; uint64_t lo; } ui128; void Rshift(ui128* data, int count) { uint64_t mask = (1uLL << count) - 1; // Set low "count" bits to 1 uint64_t save = data->hi & mask; // Save bits that fall off hi data->hi >>= count; // Shift the hi component data->lo >>= count; // Shift the lo component data->lo |= save << (64 - count); // Mask in the bits from hi return; } int main() { ui128 test = { 0xF001F002F003F004, 0xF005F006F007F008 }; printf("%016llx%016llx\n", test.hi, test.lo); Rshift(&test, 16); printf("%016llx%016llx\n", test.hi, test.lo); return 0; } Se podría usar una lógica similar para una función de desplazamiento a la izquierda, pero luego necesitaría guardar los bits superiores relevantes (más significativos) del miembro lo y enmascararlos en el valor hi desplazado:
void Lshift(ui128* data, int count) { uint64_t mask = ((1uLL << count) - 1) << (64 - count); uint64_t save = data->lo & mask; data->hi <<= count; data->lo <<= count; data->hi |= save >> (64 - count); return; }union es tu amigo, esto es lo que quieres:
#include <stdint.h> #include <stdio.h> typedef union _shift_u64{ struct _u64{ uint32_t x; uint32_t y; } __attribute__((__packed__)) U64; uint64_t x_and_y; } SHIFT_U64; int main(int argc, char* argv[]){ SHIFT_U64 test; test.U64.x = 4; test.U64.y = 8; printf("test.U64.x=%d, test.U64.y=%d, test.x_and_y=%ld\n", test.U64.x, test.U64.y, test.x_and_y); test.x_and_y<<=1; printf("test.U64.x=%d, test.U64.y=%d, test.x_and_y=%ld\n", test.U64.x, test.U64.y, test.x_and_y); test.x_and_y>>=1; printf("test.U64.x=%d, test.U64.y=%d, test.x_and_y=%ld\n", test.U64.x, test.U64.y, test.x_and_y); return 0; } EDITAR: este programa simple ilustra cómo hacerlo de otra manera, pero debe verificar el bit de transferencia y el desbordamiento de desplazamiento y el subdesbordamiento de desplazamiento usted mismo. union no se preocupa por los datos, solo tiene que asegurarse de que los datos tengan sentido. Después de compilar, redirija la salida del programa a un archivo o editor hexadecimal y lea el nivel de error del programa.
Ejemplo de Linux: ./a.out > a.out.bin; echo "errorlevel=$?"; xxd a.out.bin
#include <stdio.h> typedef union _shift_it{ struct _data{ unsigned long x : 64; unsigned long y : 64; } __attribute__((__packed__)) DATA; unsigned char x_and_y[16]; } __attribute__((__packed__)) SHIFT_IT; int main(int argc, char* argv[]){ SHIFT_IT test; int errorlevel = 0; //bitmask for shift operation static const unsigned long LEFT_SHIFTMASK64 = 0x8000000000000000; static const unsigned long RIGHT_SHIFTMASK64 = 0x0000000000000001; //test data test.DATA.x = 0x2468246824682468; //high bits test.DATA.y = 0x1357135713571357; //low bits //binary output to stdout for(int i=0; i<16; i++) putchar(test.x_and_y[i]); //left shift if(test.DATA.x & LEFT_SHIFTMASK64) errorlevel += 1; test.DATA.x <<= 1; if(test.DATA.y & LEFT_SHIFTMASK64) errorlevel += 2; test.DATA.y <<= 1; //binary output to stdout for(int i=0; i<16; i++) putchar(test.x_and_y[i]); //right shift if(test.DATA.y & RIGHT_SHIFTMASK64) errorlevel += 4; test.DATA.y >>= 1; if(test.DATA.x & RIGHT_SHIFTMASK64) errorlevel += 8; test.DATA.x >>= 1; //binary output to stdout for(int i=0; i<16; i++) putchar(test.x_and_y[i]); //right shift if(test.DATA.y & RIGHT_SHIFTMASK64) errorlevel += 16; test.DATA.y >>= 1; if(test.DATA.x & RIGHT_SHIFTMASK64) errorlevel += 32; test.DATA.x >>= 1; //binary output to stdout for(int i=0; i<16; i++) putchar(test.x_and_y[i]); //left shift if(test.DATA.x & LEFT_SHIFTMASK64) errorlevel += 64; test.DATA.x <<= 1; if(test.DATA.y & LEFT_SHIFTMASK64) errorlevel += 128; test.DATA.y <<= 1; //binary output to stdout for(int i=0; i<16; i++) putchar(test.x_and_y[i]); return errorlevel; }