Re: Младшие биты указателя
От: Кодт Россия  
Дата: 27.09.04 10:41
Оценка: 12 (1)
Здравствуйте, McSeem2, Вы писали:

MS>Мне надо вычислить значение выравнивания. То есть, есть массив байт и есть некий указатель внутри него, который может быть невыровненным, иметь, скажем, абстрактное значение 13. Допустим, мне надо выровнять его до 16 всегда в сторону увеличения. В данном случае — прибавить 3.


Адресная арифметика, однако:
BYTE* array;
BYTE* element;

ptrdiff_t offset = element-array;
offset = (offset + alignment-1) % alignment;
element = array + offset;

или, в одну строчку,
array + (element-array+alignment-1)%alignment
Перекуём баги на фичи!
Re[4]: Младшие биты указателя
От: folk Россия  
Дата: 26.09.04 03:31
Оценка: +1
Здравствуйте, folk, Вы писали:

Оказывается скобочки обязательны:
F>size_t correction = alignment - 1;
F>ptr = (void*)( size_t(ptr) + correction & ~correction );
F>
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 25.09.04 14:46
Оценка:
Мне надо вычислить значение выравнивания. То есть, есть массив байт и есть некий указатель внутри него, который может быть невыровненным, иметь, скажем, абстрактное значение 13. Допустим, мне надо выровнять его до 16 всегда в сторону увеличения. В данном случае — прибавить 3. Я делаю это так:
unsigned align = (alignment - unsigned(ptr) % alignment) % alignment;

Где alignment=16 в данном случае.
Вопрос в том, как преобразовать ptr к unsigned без предупреждений компилятора "for the possible 64-bit pointer to 32-bit unsigned conversion", причем надо сделать это без применения __int64 и прочих компиляторо-зависимых типов. Ясно, что если указатель 64 бита, а unsigned — 32, то и фиг с ней со старшей частью, на вычисление выравнивания она никак не влияет.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Младшие биты указателя
От: JakeS  
Дата: 25.09.04 17:00
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Мне надо вычислить значение выравнивания. То есть, есть массив байт и есть некий указатель внутри него, который может быть невыровненным, иметь, скажем, абстрактное значение 13. Допустим, мне надо выровнять его до 16 всегда в сторону увеличения. В данном случае — прибавить 3. Я делаю это так:

MS>
MS>unsigned align = (alignment - unsigned(ptr) % alignment) % alignment;
MS>

MS>Где alignment=16 в данном случае.
MS>Вопрос в том, как преобразовать ptr к unsigned без предупреждений компилятора "for the possible 64-bit pointer to 32-bit unsigned conversion", причем надо сделать это без применения __int64 и прочих компиляторо-зависимых типов. Ясно, что если указатель 64 бита, а unsigned — 32, то и фиг с ней со старшей частью, на вычисление выравнивания она никак не влияет.

ну и возьми младшие биты:
unsigned *u_ptr = (unsigned *)&ptr;
unsigned align = (alignment - *u_ptr % alignment) % alignment;
Re[2]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 25.09.04 17:36
Оценка:
Здравствуйте, JakeS, Вы писали:

JS>ну и возьми младшие биты:

JS>
JS>unsigned *u_ptr = (unsigned *)&ptr;
JS>unsigned align = (alignment - *u_ptr % alignment) % alignment;
JS>


Не катит. Слова "byte order" ни о чем не говорят?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Младшие биты указателя
От: WolfHound  
Дата: 25.09.04 19:54
Оценка:
Здравствуйте, McSeem2, Вы писали:

Гм. А size_t поюзать не пробовал?
VC++7.1 кушает без варнингов
    void* ptr=0;
    size_t alignment=16;
    size_t align = (alignment - size_t(ptr) % alignment) % alignment;

А если так
    void* ptr=0;
    unsigned alignment=16;
    unsigned align = (alignment - unsigned(ptr) % alignment) % alignment;

то

e:\work\physic_types\physic_types.cpp(10) : warning C4311: 'type cast' : pointer truncation from 'void *' to 'unsigned int'

... << RSDN@Home 1.1.4 rev. 185 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Младшие биты указателя
От: Xeysan  
Дата: 25.09.04 20:51
Оценка:
Посмотрите файл align.c в исходниках crt здесь: Microsoft Visual Studio .NET 2003\Vc7\crt\src.
... << RSDN@Home 1.1.4 @@subversion >>
Re[2]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 25.09.04 23:37
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Гм. А size_t поюзать не пробовал?


А можно как-нибудь без size_t, а только базовыми типами обойтись? И вообще, странно, если size_t 32 бита, должно быть в точности такое же предупреждение, а если 64 — то на фиг мне такая size_t не уперлась на 32-битной платформе. Чего-то там MS компилятор мухлюет насчет size_t
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: Младшие биты указателя
От: folk Россия  
Дата: 26.09.04 03:17
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, WolfHound, Вы писали:


WH>>Гм. А size_t поюзать не пробовал?


MS>А можно как-нибудь без size_t, а только базовыми типами обойтись? И вообще, странно, если size_t 32 бита, должно быть в точности такое же предупреждение, а если 64 — то на фиг мне такая size_t не уперлась на 32-битной платформе. Чего-то там MS компилятор мухлюет насчет size_t


На 64-битной платформе size_t будет 64-битным, ведь size_t по сути беззнаковое целое, соответствующее указателю на данные (а ptrdiff_t — знаковое).

Кстати, если заложиться на то что выравнивание является степенью двойки, то можно подстроить указатель экономнее:
size_t correction = alignment - 1;
ptr = void*( size_t(ptr) + correction & ~correction );
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[4]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 26.09.04 04:50
Оценка:
Здравствуйте, folk, Вы писали:

F>На 64-битной платформе size_t будет 64-битным, ведь size_t по сути беззнаковое целое, соответствующее указателю на данные (а ptrdiff_t — знаковое).


Нет, вопрос в том, почему на 32-х битовых платформах MS компилятор ругается на unsigned и не ругается на size_t?По идее компилятор ничего не должен знать о size_t, это не есть базовый тип C++, он должнен быть определен синонимом через typedef. А получается что либо компилятор знает, либо size_t определен как 64-битный, что есть маздай.

F>Кстати, если заложиться на то что выравнивание является степенью двойки, то можно подстроить указатель экономнее:
F>size_t correction = alignment - 1;
F>ptr = void*( size_t(ptr) + correction & ~correction );
F>

Ну это в данном случае совершенно не критично — операция очень редкая.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: Младшие биты указателя
От: folk Россия  
Дата: 26.09.04 05:42
Оценка:
Здравствуйте, McSeem2, Вы писали:

F>>На 64-битной платформе size_t будет 64-битным, ведь size_t по сути беззнаковое целое, соответствующее указателю на данные (а ptrdiff_t — знаковое).


MS>Нет, вопрос в том, почему на 32-х битовых платформах MS компилятор ругается на unsigned и не ругается на size_t?По идее компилятор ничего не должен знать о size_t, это не есть базовый тип C++, он должнен быть определен синонимом через typedef. А получается что либо компилятор знает, либо size_t определен как 64-битный, что есть маздай.


Имхо наоборот, если бы компилятор не догадывался о 64-битном size_t при 64-битном void*, то был бы маздай.
И еще мазадай в том что sizeof(size_t) > sizeof(long).
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[3]: Младшие биты указателя
От: WolfHound  
Дата: 26.09.04 07:32
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>А можно как-нибудь без size_t, а только базовыми типами обойтись? И вообще, странно, если size_t 32 бита, должно быть в точности такое же предупреждение, а если 64 — то на фиг мне такая size_t не уперлась на 32-битной платформе. Чего-то там MS компилятор мухлюет насчет size_t

Этот варнинг связан с тем что если вой код скомпиляровать под 64х битную платформу то он перестанет работать.
Как уже сказали size_t 32х битный на 32х битной платформе и 64х битный на 64х битной платформе. Компилятор об этом знает и и по этому не дает варнинг.
... << RSDN@Home 1.1.4 rev. 185 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Младшие биты указателя
От: MaximE Великобритания  
Дата: 26.09.04 10:25
Оценка:
McSeem2 wrote:

> А можно как-нибудь без size_t, а только базовыми типами обойтись?


Не вижу в чем проблема — size_t это тайпдеф на базовый тип, доступный на любом компиляторе из <stddef.h> или <cstddef>.

5.3.3 Sizeof
...
6 The result is a constant of type size_t. [Note: size_t is defined in the standard header <cstddef>(18.1). ]


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 gamma
Re[5]: Младшие биты указателя
От: _Winnie Россия C++.freerun
Дата: 26.09.04 11:05
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, folk, Вы писали:


F>>На 64-битной платформе size_t будет 64-битным, ведь size_t по сути беззнаковое целое, соответствующее указателю на данные (а ptrdiff_t — знаковое).


MS>Нет, вопрос в том, почему на 32-х битовых платформах MS компилятор ругается на unsigned и не ругается на size_t?По идее компилятор ничего не должен знать о size_t,


Знает, знает. В наше время компиляторы умнее людей

Microsoft Specific

type __w64 identifier
where:

type
One of the three types that might cause problems in code being ported from a 32-bit to a 64-bit compiler: int, long, or a pointer.
identifier
The identifier for the variable you are creating.
Remarks
The __w64 keyword lets you mark variables, such that when you compile with /Wp64 the compiler will report any warnings that would be reported if you were compiling with a 64-bit compiler.

Any typedef that has __w64 on it must be 32 bits on x86 and 64 bits on ia64.

The __w64 modifier should be specified on any typedefs that change size between 32 bit and 64 bit platforms. For any such type, __w64 should appear only on the 32-bit definition of the typedef. For example:

#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef _W64 unsigned int size_t;
#endif
__w64 is ignored if the compilation does not use /Wp64.

Example
// __w64.cpp
// compile with: /W3 /Wp64
typedef int Int_32;
#ifdef _WIN64
typedef __int64 Int_Native;
#else
typedef int __w64 Int_Native;
#endif

int main()
{
Int_32 i0 = 5;
Int_Native i1 = 10;
i0 = i1; // C4244 64-bit int assigned to 32-bit int

// char __w64 c; error, cannot use __w64 on char
}
END Microsoft Specific


ЗЫ.
А для чего нужен тег [ msdn ] ? Я им пытался воспользоваться...
Правильно работающая программа — просто частный случай Undefined Behavior
Re[6]: Младшие биты указателя
От: Alex Reyst Россия  
Дата: 26.09.04 12:10
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>А для чего нужен тег [ msdn ] ? Я им пытался воспользоваться...


Автоматическое формирование URL запроса к MSDN с поиском заключенной в тег фразы.
Все, что здесь сказано, может и будет использоваться против меня...
Re[3]: Младшие биты указателя
От: JakeS  
Дата: 26.09.04 15:39
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, JakeS, Вы писали:


JS>>ну и возьми младшие биты:

JS>>
JS>>unsigned *u_ptr = (unsigned *)&ptr;
JS>>unsigned align = (alignment - *u_ptr % alignment) % alignment;
JS>>


MS>Не катит. Слова "byte order" ни о чем не говорят?


Говорят и очень много. на x86 порядок обратный, поэтому unsigned *u_ptr = (unsigned *)&ptr есть указатель на младший байт, на младшее слово, и на младшее двойное слово.
Re[7]: Младшие биты указателя
От: Aera Беларусь  
Дата: 26.09.04 17:57
Оценка:
Здравствуйте, Alex Reyst, Вы писали:

AR>Здравствуйте, _Winnie, Вы писали:


_W>>А для чего нужен тег [ msdn ] ? Я им пытался воспользоваться...


AR>Автоматическое формирование URL запроса к MSDN с поиском заключенной в тег фразы.


Может надо было назвать его [ rtfm ] ?
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
--
RedApe
Re[5]: Младшие биты указателя
От: Aera Беларусь  
Дата: 26.09.04 17:57
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, folk, Вы писали:


F>>На 64-битной платформе size_t будет 64-битным, ведь size_t по сути беззнаковое целое, соответствующее указателю на данные (а ptrdiff_t — знаковое).


MS>Нет, вопрос в том, почему на 32-х битовых платформах MS компилятор ругается на unsigned и не ругается на size_t?По идее компилятор ничего не должен знать о size_t, это не есть базовый тип C++, он должнен быть определен синонимом через typedef. А получается что либо компилятор знает, либо size_t определен как 64-битный, что есть маздай.


size_t такой же стандартный тип как и unsigned. А то что он у VC объявлен как typedef ни о чем не говорит. А ругается он не потому, что у тебя что-то не так, а что проблемы возникнут при компиляции этого кода под 64-битной платформой.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
--
RedApe
Re[6]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 26.09.04 23:30
Оценка:
Здравствуйте, Aera, Вы писали:

A>size_t такой же стандартный тип как и unsigned. А то что он у VC объявлен как typedef ни о чем не говорит. А ругается он не потому, что у тебя что-то не так, а что проблемы возникнут при компиляции этого кода под 64-битной платформой.


size_t не является базовым типом данных C++. Period.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 26.09.04 23:31
Оценка:
Здравствуйте, JakeS, Вы писали:

MS>>Не катит. Слова "byte order" ни о чем не говорят?


JS>Говорят и очень много. на x86 порядок обратный, поэтому unsigned *u_ptr = (unsigned *)&ptr есть указатель на младший байт, на младшее слово, и на младшее двойное слово.


Не Интелом Единым, как говорится...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Младшие биты указателя
От: Nuald Россия http://nuald.blogspot.com
Дата: 27.09.04 01:10
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Мне надо вычислить значение выравнивания. То есть, есть массив байт и есть некий указатель внутри него, который может быть невыровненным, иметь, скажем, абстрактное значение 13. Допустим, мне надо выровнять его до 16 всегда в сторону увеличения. В данном случае — прибавить 3. Я делаю это так:


А если посмотреть с другой стороны. Вам нужно выравнивание по последним четырем битам. Что мешает сделать следующее:
template <class T> T align(T value, unsigned char bitsCount) {
    assert(sizeof T <= bitsCount);
    T alignment = 0;
    for (unsigned char i = 0; i < bitsCount; ++i) {
        alignment <<= 1;
        alignment |= 1;
    }
    T piece = value & alignment;
    T result = value >> bitsCount;
    if (piece != 0) {
        ++result; //здесь может быть другая функция, смотря как конкретно вам нужно выравнивать
    }
    return result << bitsCount;
}
Re[5]: Младшие биты указателя
От: JakeS  
Дата: 27.09.04 10:06
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, JakeS, Вы писали:


MS>>>Не катит. Слова "byte order" ни о чем не говорят?


JS>>Говорят и очень много. на x86 порядок обратный, поэтому unsigned *u_ptr = (unsigned *)&ptr есть указатель на младший байт, на младшее слово, и на младшее двойное слово.


MS>Не Интелом Единым, как говорится...


ну x86 — это не только интел. Кстати а у каких процессоров по другому?
Re[6]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 27.09.04 15:54
Оценка:
Здравствуйте, JakeS, Вы писали:

JS>Кстати а у каких процессоров по другому?


PPC, SGI, Sun, да полно. Там первый байт — это старший байт
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[2]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 27.09.04 16:00
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Адресная арифметика, однако:

К>
К>BYTE* array;
К>BYTE* element;

К>ptrdiff_t offset = element-array;
К>offset = (offset + alignment-1) % alignment;
К>element = array + offset;
К>

К>или, в одну строчку,
К>
К>array + (element-array+alignment-1)%alignment
К>


Все правильно. Но если мне действительно потребуется выравнивание на 16 (например, для оптимизации SSE2 операций), то array сам по себе должен иметь выравнивание на 16. C++ такой гарантии не дает.
О! конгениально!
BYTE* array = 0;

Далее по тексту и никаких size_t
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: Младшие биты указателя
От: Кодт Россия  
Дата: 27.09.04 17:06
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>О! конгениально!

MS>BYTE* array = 0;

Вообще-то, адресная арифметика определена только над указателями одного и того же домена.
Нулевой указатель не принадлежит ни одному домену, поэтому с лёгкостью необычайной ты получишь UB.
Впрочем, в tiny и small моделях памяти (а виндовская flat — это 32-битный аналог tiny) это не страшно.
Перекуём баги на фичи!
Re[4]: Младшие биты указателя
От: McSeem2 США http://www.antigrain.com
Дата: 27.09.04 19:20
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Вообще-то, адресная арифметика определена только над указателями одного и того же домена.

К>Нулевой указатель не принадлежит ни одному домену, поэтому с лёгкостью необычайной ты получишь UB.
К>Впрочем, в tiny и small моделях памяти (а виндовская flat — это 32-битный аналог tiny) это не страшно.

Ииии... тоже верно. Остаемся с size_t...
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: Младшие биты указателя
От: JakeS  
Дата: 28.09.04 12:02
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Здравствуйте, Кодт, Вы писали:


К>>Вообще-то, адресная арифметика определена только над указателями одного и того же домена.

К>>Нулевой указатель не принадлежит ни одному домену, поэтому с лёгкостью необычайной ты получишь UB.
К>>Впрочем, в tiny и small моделях памяти (а виндовская flat — это 32-битный аналог tiny) это не страшно.

MS>Ииии... тоже верно. Остаемся с size_t...


кстати, объясните такую фишку: int type
Лень лезть в стандарт. Насколько я понимаю тип int соответствует размеру регистра процессора, т.е. для 64битного процессора его размер 64бита и соответствует размеру указателя. таким образом
void *ptr;
int *pPtr = &ptr;

всегда корректно.
Re[6]: Младшие биты указателя
От: Antikrot  
Дата: 28.09.04 12:18
Оценка:
Здравствуйте, JakeS, Вы писали:
JS>Насколько я понимаю тип int соответствует размеру регистра процессора, т.е. для 64битного процессора его размер 64бита и соответствует размеру указателя.
Нет, не обязательно. Например, в Intel C++ IA64 (и кажется AMD64) размер int'а — 32 бита.
Re[6]: Младшие биты указателя
От: Кодт Россия  
Дата: 28.09.04 12:23
Оценка:
Здравствуйте, JakeS, Вы писали:

JS>кстати, объясните такую фишку: int type

JS>Лень лезть в стандарт. Насколько я понимаю тип int соответствует размеру регистра процессора, т.е. для 64битного процессора его размер 64бита и соответствует размеру указателя. таким образом
JS>
JS>void *ptr;
JS>int *pPtr = &ptr;
JS>

JS>всегда корректно.

Совершенно некорректно.

int соответствует размеру целочисленного регистра.
void* — представлению адреса данных для конкретной модели памяти.
void(*)() — представлению адреса кода для конкретной модели памяти.

У IA32: помимо flat модели, есть ещё сегментная, в которой адреса состоят из селектора и смещения (которое хранится в регистре общего назначения).
Аналогично — у 8086, причём в large модели адрес и указатель 32-битные (16 бит на селектор и 16 на смещение), в huge — указатель 20-битный (сплошная нумерация адресов), в small — 16 (только смещение).

На не-интеловской архитектуре — тем более бывают варианты.
Перекуём баги на фичи!
Re[7]: Младшие биты указателя
От: Antikrot  
Дата: 28.09.04 13:00
Оценка:
Здравствуйте, Кодт, Вы писали:

К>int соответствует размеру целочисленного регистра.

Ни в коем случае нельзя на это рассчитывать. С большой вероятностью на 64-битке int будет 32-битным... я уже пример приводил.

Самый простой способ убедиться — набрать в гугле "sizeof(int) 64 bit" и посмотреть первые две ссылки.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.