Утвержденный синтаксис для обработки необработанных указателей - PullRequest
6 голосов
/ 18 февраля 2010

Я делаю процедуру копирования блоков памяти, и мне нужно иметь дело с блоками сырой памяти в эффективных блоках. Мой вопрос не о специальной подпрограмме копирования, которую я делаю, а о том, как правильно проверить выравнивание необработанных указателей в C.

У меня есть необработанный указатель памяти, скажем, он уже приведен как ненулевой символ *. В моей архитектуре я могу очень эффективно копировать память в 64-байтовых чанках, когда она выровнена по 64-байтным чанкам. Таким образом, (стандартная) хитрость заключается в том, что я сделаю простую копию 0-63 байта "вручную" в голове и / или хвосте, чтобы преобразовать копию из произвольного символа * произвольной длины в 64-байтовый выровненный указатель с некоторым кратным длиной 64 байта.

Теперь вопрос в том, как юридически «исследовать» указатель, чтобы определить (и манипулировать) его выравниванием? Очевидный способ - преобразовать его в целое число и просто изучить биты:

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

Обратите внимание, что здесь я понимаю, что alignPointer не указывает на ту же память, что и указатель ... это указатель «с округлением», на котором я могу вызвать свою подпрограмму эффективного копирования, и я буду обрабатывать любые другие байты в начало вручную.

Но компиляторы (оправданно) сходят с ума при приведении указателя в целое число. Но как еще можно проверить младшие биты указателя в LEGAL C и манипулировать ими? В идеале, чтобы с разными компиляторами я не получал ошибок или предупреждений.

Ответы [ 4 ]

7 голосов
/ 18 февраля 2010

Для целочисленных типов, достаточно больших для размещения указателей, C99 stdint.h имеет:

Для длин данных есть:

, которые существовали задолго до C99.

Если у вашей платформы их нет, вы можете максимизировать переносимость вашего кода, продолжая использовать имена этих типов и подходя для них typedef s.

1 голос
/ 18 февраля 2010

Я не думаю, что в прошлом люди так неохотно делали свои собственные битовые удары, но, возможно, нынешнее настроение "не трогай это" будет способствовать тому, чтобы кто-то создавал какую-то стандартную библиотеку для выравнивания указателей,Не имея какого-то официального API, у вас нет выбора, кроме как и И или ваш путь.

0 голосов
/ 18 февраля 2010

Приведение указателей к целым числам и из них допустимо, но результаты определяются реализацией. См. Раздел 6.3.2.3 стандарта. Похоже, что предполагается, что результаты - это то, чего ожидают все, кто знаком с системой, и на самом деле это обычно происходит на практике.

Если рассматриваемая архитектура может эффективно взаимозаменяемо манипулировать указателями и целыми числами, и вопрос заключается только в том, сработает ли она на всех компиляторах для этой системы, тогда ответ заключается в том, что она, вероятно, все равно будет работать.

(Конечно, если бы я писал этот код, я бы подумал, что это нормально как есть, пока не доказано обратное. Мой опыт показывает, что компиляторы для данной системы ведут себя очень схожим образом на этом уровне; язык ассемблера просто предлагает конкретный подход, который все потом предпримут.)

«Вероятно, работает» - это не очень хороший общий совет, поэтому я предлагаю просто написать работающий код, окружить его достаточно подходящими #ifdef s, чтобы его компилировали только известные компиляторы, и откладывал до memcpy в других случаях.

#ifdef редко бывает идеальным, но он довольно легкий по сравнению с другими возможностями. И если требуется поведение, определяемое реализацией, или специфичные для компилятора приемы, параметры в любом случае довольно ограничены.

0 голосов
/ 18 февраля 2010

Вместо int попробуйте тип данных, размер которого гарантированно равен указателю (INT_PTR в Win32 / 64). Может быть, компилятор не слишком взбесится. :) Или используйте объединение, если 64-битная совместимость не важна.

...