2015-04-22 2 views
11

Учитывая требование, чтобы мне нужно было сохранить значение «общего» указателя в структуре и не интересоваться самой заостренной памятью, я считаю более семантически правильным хранить его как intptr_t, чем void*. Вопрос в том, лучше ли подходит uintptr_t или нет, а когда один предпочтительнее другого?Когда uintptr_t предпочитается над intptr_t?

+4

Умм .. это не то, для чего пустота *? – mjs

+1

Я не хочу, чтобы клиенты этой структуры когда-либо думали, что значение _pointee_ имеет какой-либо интерес, и, создав поле 'intptr_t' или' uintptr_t', я надеюсь, что он станет ясно, что это значение _interinter_ интересно. Пожалуйста, дайте мне знать, если я буду лаять неправильное дерево, рассуждая так :-) –

+2

Это ваша интерпретация: другие могут даже не знать, для чего предназначен 'intptr_t'. Я бы использовал 'void *' и * комментарий *, чтобы указать, что вы только заботитесь о адресе памяти. Что-то вроде: 'void * address;/* Нам просто нужен адрес памяти */'. – edmz

ответ

7

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

Помните, что в чисто стандартном сравнении с C-указателем имеется приблизительно значение только для указателей на одинаковые агрегированные данные. Вам, вероятно, не разрешено сравнивать два результата от malloc, например. чтобы сохранить отсортированный массив указателей.

Я бы сохранил их как void*, а также как uintptr_t. У подписанного intptr_t есть неудобства для разделения отрицательных и положительных чисел, и там, где они исходят из значительных указателей приложений, это, вероятно, не приветствуется.

Обратите внимание, что void* не может быть разыменовываются: как uintptr_t, вы есть бросить его сделать что-то полезное с данными указываемого адреса; однако void* указатели могут быть переданы подпрограммы, такие как memset

PS. Я предполагаю обычный процессор (например, некоторые x86, PowerPC, ARM, ...) с плоским виртуальным адресным пространством. Возможно, вы можете найти экзотические процессоры - некоторые DSP - с очень значительными различиями (и, возможно, на которых intptr_t не всегда имеет значение, помните, что в 1990-х годах Cray Y-MP суперкомпьютеры sizeof(long*) != sizeof(char*), тогда C99 не существовало, и я не уверен, что его может быть значимым на таких машинах)

+0

Я работал на Cray T90 с Unicos.'long *' и 'char *' были одного и того же размера (64 бит), но 'char *' использовали старшие 3 бита для хранения смещения байтов, поскольку машинные адреса указывали на 64-битные слова (все это управлялось в программном обеспечении). Был ли более старый Y-MP? –

+0

Я забыл детали, но кастинг (я забыл в каком направлении) '(char *)' to/from '(long *)' был проблемой ... –

+2

В T90 конверсии integer и pointer просто скопировали биты. Если указатель 'char *' имеет ненулевое смещение, преобразование его в 'long *' приведет к недопустимому указателю, так как 3 старших бита будут частью адреса (а фактическое адресное пространство не было почти что большой). Я когда-то видел некоторый код, который вычислял разницу между двумя указателями, сначала преобразовывая их в целые числа; Я указал, что выпрямление прямого указателя проще и имеет силу фактически действующего. –

9

Это звучит очень странно, так как это потребует отливок. A void * в C имеет огромное преимущество в том, что он преобразует в/из других типов указателей объектов без следов, что является чистым способом.

Сказанное uintptr_t может иметь смысл, если вы хотите делать что-то с битами указателя, которые вы не можете сделать так же разумно с помощью целого числа со знаком (например, сдвигая их вправо, например).

+0

_ «Это звучит очень странно, так как это потребует отливок» - ну да. Я не хочу, чтобы клиенты этой структуры когда-либо думали, что значение _pointee_ представляет какой-либо интерес, и, создав поле 'intptr_t' или' uintptr_t', я надеюсь, что он будет ясно, что это самое значение _interinter_, которое интересно , Пожалуйста, дайте мне знать, если я буду лаять неправильное дерево, рассуждая так :-) –

+2

@JohannGerell Трудно быть окончательным, конечно. Но поскольку вся точка «void *» заключается в том, что ее нельзя разыменовать, так как нет никакой информации о типе указателя, я бы сказал, что это именно то, что она сообщает. – unwind

+0

, вам может потребоваться использовать 'intptr_t' для получения [подписанного расширения на канонических адресах x86_64] (http://stackoverflow.com/q/16198700/995714) –

0

Если вы хотите управлять значением арифметически (например, для его шифрования), у вас будет гораздо больше гибкости с неподписанным типом (где арифметические обходы), чем с подписанным типом (где арифметическое переполнение дает неопределенное поведение).