2010-02-17 8 views
6

Estoy haciendo una rutina de copia en bloque de memoria y necesito tratar con bloques de memoria sin procesar en trozos eficientes. Mi pregunta no es sobre la rutina de copia especializada que estoy haciendo, sino cómo examinar correctamente la alineación del puntero sin procesar en C.Sintaxis aprobada para la manipulación del puntero sin formato

Tengo un puntero de memoria sin procesar, digamos que ya está emitido como un carácter no nulo * . En mi arquitectura, puedo copiar de manera muy eficiente la memoria en trozos de 64 bytes CUANDO ESTÁ ALINEADA EN UN COMPONENTE DE 64 BYTE. Entonces, el truco (estándar) es que haré una copia simple de 0-63 bytes "manualmente" en la cabeza y/o la cola para transformar la copia de un carácter arbitrario * de longitud arbitraria a un puntero alineado de 64 bytes con algunos valores múltiples de 64 bytes de longitud.

Ahora la pregunta es, ¿cómo legalmente "examinar" un puntero para determinar (y manipular) su alineación? La forma más obvia es para su emisión en un entero y simplemente examinar los bits:

char *pointer=something. 
int p=(int)pointer; 
char *alignedPointer=(char *)((p+63)&~63); 

Obsérvese en este punto me di cuenta que alignedPointer no apunta a la misma memoria que el puntero ... este es el "redondea" puntero al que puedo llamar mi rutina de copia eficiente, y manejaré cualquier otro byte al comienzo manualmente.

Pero los compiladores (justificadamente) se vuelven locos al convertir un puntero en un número entero. Pero, ¿de qué otra manera puedo examinar y manipular los bits inferiores del puntero en LEGAL C? Lo ideal sería que con diferentes compiladores no obtuviera errores ni advertencias.

+0

Eso debería estar bien siempre que 'int' tenga el mismo tamaño que los tipos de puntero. –

+0

También es posible que desee echar un vistazo a http://stackoverflow.com/questions/1898153/how-to-determine-if-memory-is-aligned-testing-for-alignment-not-aligning/1898194 –

+0

Ah, pero presupone que los punteros se almacenan en binario de MSB a LSB. ¿Que tenemos? * comportamiento indefinido! * (dicho de la misma manera que el tipo de arma letal dice * ¡inmunidad diplomática! *) El hecho de que funcione en el mundo real no lo hace menos indefinido. ;-) –

Respuesta

7

Para los tipos de enteros que son lo suficientemente grande para contener punteros, C99 stdint.h tiene:

Para los datos de longitudes de allí son:

que han existido desde mucho antes de C99.

Si la plataforma no tiene estos, se puede maximizar la portabilidad de su código por dejar de utilizar estos nombres de tipos, y haciendo adecuados typedef s para ellos.

+0

+1 me ganó. –

+0

ah, pero ¿cómo se obtiene un puntero * alineado * de uno no alineado? – JustJeff

0

En lugar de int, intente con un tipo de datos que garantice tener el mismo tamaño que un puntero (INT_PTR en Win32/64). Quizás el compilador no se asuste demasiado. :) O use una unión, si la compatibilidad de 64 bits no es importante.

1

No creo que en el pasado la gente fuera tan reacia a hacer sus propios ataques de bits, pero tal vez el actual estado de ánimo de "no tocar eso" sería propicio para que alguien cree algún tipo de biblioteca estándar para alinear punteros. Al carecer de algún tipo de API oficial, no tienes más remedio que AND y O a tu manera.

+1

+1 En el pasado, no existía el * comportamiento indefinido *. Si su compilador hizo lo que usted quería que hiciera, eso fue suficiente. –

0

Buscar punteros hacia y desde enteros es válido, pero los resultados están definidos por la implementación. Ver la sección 6.3.2.3 de la norma. La intención parece ser que los resultados son los que cualquier persona familiarizada con el sistema podría esperar, y de hecho parece ser así en la práctica.

Si la arquitectura en cuestión puede manipular de manera eficiente punteros y enteros de manera intercambiable, y la cuestión es si funcionará en todos los compiladores para ese sistema, entonces la respuesta es que probablemente lo hará de todos modos.

(Ciertamente, si estuviera escribiendo este código, pensaría que está bien tal como está, hasta que se demuestre lo contrario. Mi experiencia ha sido que los compiladores de un sistema dado se comportan de manera muy similar en este tipo de nivel; el lenguaje simplemente sugiere un enfoque particular, que todos toman).

"Probablemente funciona" no es un consejo general muy bueno, así que mi sugerencia sería simplemente escribir el código que funcione, rodearlo lo suficientemente adecuado #ifdef s que solo el (los) compilador (es) conocido (s) compilarán y diferirán al memcpy en otros casos.

#ifdef es raramente ideal, pero es bastante ligero en comparación con otras posibilidades. Y si se necesitan comportamientos definidos por la implementación o trucos específicos del compilador, las opciones son bastante limitadas de todos modos.

+0

"el lenguaje ensamblador solo sugiere un enfoque particular" - Solo voy a empezar a utilizar esta frase en debates de software, independientemente de su aplicabilidad. – notJim

Cuestiones relacionadas