Границы пустых указателей в ANSI C89 / ISO C90 - PullRequest
0 голосов
/ 22 января 2009

Есть ли способ портативно определить верхнюю и нижнюю границу значений пустого указателя в ANSI C89 / ISO C90? (У меня в настоящее время нет копии стандарта со мной (у меня есть одна дома). Конечно, если значения void-указателя гарантированно не подписаны, эта задача тривиальна (через sizeof (void *)), однако я не могу вспомнить, гарантировано ли это или нет. Я могу придумать несколько очень неэффективных алгоритмов (увеличение до переполнения и т. д.), но я хотел бы знать, есть ли у кого-либо относительно дешевый (с точки зрения сложности времени) и переносимый способ вычисления этих границ.)

- EDIT -

Также: Существует ли переносимый способ определения достоверности значений указателя?

Почему: Это возникло в дискуссии с коллегой, и это поставило меня в тупик. Я не знаю, над чем он работает, но я просто хочу знать, потому что мне интересно! : -)

Ответы [ 6 ]

4 голосов
/ 22 января 2009

Нет портативного способа определить, является ли данный указатель действительным или нет. Вы должны знать, с какой системой памяти вы имеете дело. В зависимости от операционной системы и процессора может существовать или не существовать способ запроса таблиц страниц менеджера виртуальной памяти для определения допустимых диапазонов указателей.

Например, в Linux вы можете просмотреть специальный файл mmap в /proc, чтобы получить карту виртуальной памяти процесса. Вот пример cat считывания собственной карты памяти:

$ cat /proc/self/mmap
08048000-0804c000 r-xp 00000000 09:00 5128276                            /bin/cat
0804c000-0804d000 rw-p 00003000 09:00 5128276                            /bin/cat
0804d000-0806e000 rw-p 0804d000 00:00 0                                  [heap]
f7ca7000-f7e40000 r--p 00000000 09:00 3409654                            /usr/lib/locale/locale-archive
f7e40000-f7e41000 rw-p f7e40000 00:00 0 
f7e41000-f7f68000 r-xp 00000000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f68000-f7f6d000 r--p 00127000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f6d000-f7f6f000 rw-p 0012c000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f6f000-f7f72000 rw-p f7f6f000 00:00 0 
f7f83000-f7f85000 rw-p f7f83000 00:00 0 
f7f85000-f7f9a000 r-xp 00000000 09:00 2637871                            /lib/ld-2.3.6.so
f7f9a000-f7f9c000 rw-p 00014000 09:00 2637871                            /lib/ld-2.3.6.so
ff821000-ff836000 rw-p 7ffffffea000 00:00 0                              [stack]
ffffe000-fffff000 r-xp ffffe000 00:00 0                                  [vdso]

Вы можете видеть диапазоны действительных указателей, а также биты, указывающие, является ли память (r) доступной, (w) пригодной, e (x) пригодной для чтения или (p) повторно (то есть не выгруженной на диск) .

0 голосов
/ 23 января 2009

За исключением региона, который соответствует NULL, нет никаких (переносимых) ограничений на адреса памяти вообще. Достаточно защищенная ОС может использовать различные механизмы ЦП / ОС для обеспечения каждого процесса случайными и хорошо распределенными адресами при каждом вызове malloc (), а независимый от положения исполняемый файл плюс ASLR могут позволить коду запускаться также с любого адреса.

0 голосов
/ 22 января 2009

Вы должны различать целочисленное значение, к которому void * может быть приведено из действительного битового шаблона в памяти - приведение void * к целочисленному типу может включать преобразования!

Предполагая sizeof(void *) == sizeof(long), для void * p следующее может быть ложным:

((long)p) == *((long *)&p)

Кроме того, стандарт не указывает, является ли даже целочисленным типом, достаточно большим, чтобы содержать значения всех допустимых указателей!

Следовательно, просто нет портативного способа делать то, что вы хотите делать ...

0 голосов
/ 22 января 2009

void * всегда достаточно большой, чтобы содержать указатель на адресуемую память. Любое другое использование строго запрещено бейсбольной ассоциацией высшей лиги.

Пример: dec-10 представлял собой 36-битную архитектуру с 36-битными словами. Тем не менее, адреса были 18 бит, и вы можете хранить 2 указателя в любом регистре / слове.

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

Наконец - никогда не используйте 'void *' для хранения указателя на объект или указателя на член в C ++. Многие реализации компиляторов фактически используют несколько «физических» указателей для реализации множественного наследования конкретных (или частично конкретных) классов. В действительности это почти никогда не происходит, потому что очень немногие люди используют множественное наследование таким образом, а когда они это делают, очень редко срезают и не срезают указатели. Когда это происходит, очень трудно понять, что произошло.

0 голосов
/ 22 января 2009

Я знаю, что в Win32 64-битные указатели имеют расширенный знак. Забавно проверять 32-битный мини-дамп с 64-битной машины, если вы не подписываете указатели расширений.

См. здесь о том, как работает 64-битный указатель (POINTER_64) на Win32.

0 голосов
/ 22 января 2009

Указатели гарантированно не подписаны. Но с какой стати вы хотите найти границы? «Все между 0x00000001 и 0xffffffff» не является действительно полезным тестом, поскольку число допустимых указателей будет небольшим подмножеством.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...