Утвержденный синтаксис для манипулирования необработанным указателем

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

У меня есть необработанный указатель памяти, допустим, он уже приведен как ненулевой char *. В моей архитектуре я могу очень эффективно копировать память 64-байтовыми фрагментами, КОГДА ОНА ВЫРАВНИВАЕТСЯ С 64-байтовым фрагментом. Таким образом, (стандартный) трюк заключается в том, что я сделаю простую копию 0-63 байта «вручную» в начале и / или хвосте, чтобы преобразовать копию из произвольного char * произвольной длины в 64-байтовый выровненный указатель с несколькими длиной 64 байта.

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

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

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

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


person SPWorley    schedule 17.02.2010    source источник
comment
Это должно быть нормально, если int того же размера, что и типы указателя.   -  person Carl Norum    schedule 18.02.2010
comment
Вы также можете взглянуть на stackoverflow.com/questions/1898153/   -  person Robert Paulson    schedule 18.02.2010
comment
Ах, но вы предполагаете, что указатели хранятся в двоичном формате от MSB до LSB. Что у нас есть? неопределенное поведение! (сказано так же, как парень со смертоносным оружием говорит дипломатический иммунитет!) То, что оно работает в реальном мире, не делает его менее неопределенным. ;-)   -  person Richard Pennington    schedule 18.02.2010
comment
@pennington - почему вы говорите, что предполагается прямой порядок байтов? Если вы скажете & 0x0f, значение 0x0F будет однозначным. Он будет сохранен компилятором с тем же порядком байтов, что и указатели. Не так ли? Теперь, если вы приведете указатель к массиву байтов, вам действительно придется беспокоиться.   -  person JustJeff    schedule 18.02.2010
comment
Неужели система memcpy( ) на вашей платформе действительно не настроена для использования этого преимущества?   -  person Stephen Canon    schedule 18.02.2010
comment
@JustJeff: Пытаюсь быть смешным. Нет гарантии, что указатели хранятся в двоичном формате. ;-)   -  person Richard Pennington    schedule 18.02.2010
comment
@pennington - ой! Да, это верно. давайте никогда не забудем мрачные дни 8088 года! знак равно   -  person JustJeff    schedule 18.02.2010
comment
@justjeff значение int & 0x0f однозначно. Проблема в том, что вы начали с указателя и солгали компилятору, когда перешли (int) указатель. НА машине, которая хранит указатели в формате, отличном от простых целых чисел, тогда вы тост. Я работал на машинах, на которых указатели, приведенные к целым числам, не имеют смысла при манипулировании операциями int mask (если вы не знаете формат указателей для начала). Просто чтобы добавить изюминку в эту систему, указатели NULL были 0xFFFFFFFF   -  person pm100    schedule 18.02.2010
comment
@ pm100 Я не знаком с такими машинами (кроме сегментированных указателей 8088, для которых вы все еще могли бы манипулировать несколькими младшими битами, я думаю). Мне было бы интересно услышать, о каких машинах вы имеете в виду.   -  person Craig McQueen    schedule 18.02.2010
comment
Какую архитектуру отстойной нечисти вы используете, если CRT-реализация memcpy () этого еще не делает? Собираю тут советы по покупке.   -  person Hans Passant    schedule 18.02.2010
comment
Я видел это на компиляторах, нацеленных на системы с модифицированной версией общей архитектуры (например, MIPS или POWER). Это раздражает, но не совсем раздражает :) Компилятор просто поставляется с общей библиотекой времени выполнения, которая использует только стандартный набор инструкций. Похоже, что компании, ориентированные на HW, не всегда имеют ресурсы, ориентированные на программное обеспечение, чтобы написать собственную библиотеку.   -  person    schedule 20.02.2010
comment
Да, но memcpy это как ... самый простой из базовых. Если вы собираетесь оптимизировать что-нибудь вообще, вы оптимизируете memcpy.   -  person Stephen Canon    schedule 20.02.2010


Ответы (4)


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

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

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

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

person Craig McQueen    schedule 17.02.2010
comment
ах, но как получить указатель выровненный из невыровненного? - person JustJeff; 18.02.2010

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

person JustJeff    schedule 17.02.2010
comment
+1 Раньше не было такого понятия, как неопределенное поведение. Если ваш компилятор делал то, что вы хотели, этого было достаточно. - person Richard Pennington; 18.02.2010

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

person Seva Alekseyev    schedule 17.02.2010

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

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

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

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

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

person Community    schedule 18.02.2010
comment
ассемблер просто предлагает определенный подход - я просто собираюсь начать использовать эту фразу в дебатах по программному обеспечению, независимо от применимости. - person davidtbernal; 20.08.2010