преобразование длины в указатель

#c

#c

Вопрос:

Может ли это приведение завершиться неудачей и когда?

 long x=-1;
long y = (long)(void*)x;
assert(x==y);
  

Более конкретно, как определить, подходит ли приведенное выше приведение во время компиляции.

Комментарии:

1. Просто догадываюсь: это для pthread_create ?

Ответ №1:

Более переносимый способ (в стандартном варианте C99) заключается в том, чтобы #include <stdint.h> затем приводить указатели к intptr_t (и обратно). Этот целочисленный тип гарантированно будет размером с указатель.

Комментарии:

1. Обратите внимание, что OP приводит integer-> pointer-> integer, который в моем понимании стандарта немного менее определен, чем pointer-> integer-> указатель.

2. Я забыл детали, и я думаю, что стандарты изменились в этом аспекте. На практике указатели на функции являются указателями, теоретически это не совсем так.

3. @Basile: разница здесь не в теории и практике — скорее, стандарт C должен справляться с существующими архитектурами, где указатели кода и данных имеют представления разных размеров (например, far и near); даже сегодня существуют микроконтроллеры без плоской модели памяти, и вам даже не нужно искать экзотические архитектуры — любой процессор x86 все еще может использоваться в реальном режиме

4. Я думаю, что комитет POSIX в какой-то момент рассматривал возможность иметь dlsym и другую функцию (возможно dlfsym ?) для работы с указателями на функции, размер которых отличается от размера указателей на данные, но они отказались от этой идеи, так что, по крайней мере, в области POSIX, практически говоря, указатели на функции имеют тот же размер, что и указатели на данные.

Ответ №2:

Переносимо нет. Я знаю даже реализацию, в которой это приведет к сбою. реальный режим x86 с моделями памяти крошечного, малого и среднего размера. long имеет 32 бита, а указатели — 16 бит. Другие микроконтроллеры с гарвардской архитектурой, вероятно, тоже выйдут из строя.

Ответ №3:

Насколько я помню, это не приведет к сбою, учитывая, что вы исправили тип y на (long)(void*) .

Комментарии:

1. Хм? «(long)(void*)» не является типом. Это серия из двух приведений, сначала приведение к void* , а затем приведение к long .

Ответ №4:

Это может привести к сбою в архитектурах, где long int и указатель имеют разный размер. Некоторые 64-битные архитектуры имеют такое поведение. Как говорит Basile, используйте вместо этого intptr_t, если это доступно в вашей системе.

Вы можете обнаружить эту ситуацию во время компиляции следующим образом:

 #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
STATIC_ASSERT((sizeof(void*) > sizeof(long)), incompatible_pointer_size);
  

Комментарии:

1. Нет, sizeof не может отображаться в выражениях препроцессора, поэтому приведенное выше, к сожалению, неверно.

2. Верно в отношении препроцессора, но идея, которая sizeof (void*) > sizeof (long) может быть правдой, является важным сообщением здесь.

3. @BasileStarynkevitch прав, вы должны использовать трюк со статическим утверждением. Я отредактирую ответ.

4. Это уже отредактированный?