2013-07-17 4 views
-1

Если я объявляюМожем ли мы иметь операции между int * и unsigned int?

int x = 5 ; 
int* p = &x; 
unsigned int y = 10 ; 
cout << p+y ; 

Является ли это допустимым, что нужно сделать в C++, и если нет, то почему?

У этого нет практического использования, но возможно ли это?

+4

Целые числа не являются указателями. Указатели не являются целыми числами. –

+2

«Указатель - это в основном целое число без знака». Нет, это не так. Указатель и целое - это совершенно разные абстракции. Основное представление не имеет значения (и побитовое кастинг - зло, поэтому даже не думайте об этом). –

+0

Да, я понимаю, что я говорю, что это не указатель на неопределенное целочисленное значение – AbKDs

ответ

4

Математика действительна; результирующий указатель - нет.

Когда вы говорите ptr + i (где ptr является int*), который вычисляет адрес в междунар Это i * sizeof(int) байт прошлых ptr. В этом случае, поскольку ваш указатель указывает на один int, а не на массив из них, вы понятия не имеете (и C++ не говорит), что находится в p+10.

Если, однако, вы что-то вроде

int ii[20] = { 0 }; 
int *p = ii; 
unsigned int y = 10; 
cout << p + y; 

Тогда вы бы указатель вы могли бы реально использовать, потому что она по-прежнему указывает на некоторые места в массиве он первоначально указывал в.

+0

Ссылка на страницу справки по арифметике указателя, вероятно, также принесет пользу OP. –

+4

Вы, однако, можете добавить 1 к указателю. C++ - это хорошо, если у вас есть указатель, указывающий на позицию памяти только за конец чего-то, если вы не разыщите его. – paddy

+1

@paddy Это ужасающе ... –

0

Переменная типа int является переменной, способной содержать целочисленное значение. Переменная типа int* является указателем переменной, которая может содержать целочисленное значение.

Каждый тип указателя имеет одинаковый размер и содержит те же элементы: адрес памяти, размер которого составляет 4 байта для 32-разрядных архитектур и 8 байтов для 64-разрядных архитектур. Их отличает тип переменной: poiting to.

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

Арифметические операции с указателями возможны, но они не будут делать то, что вы думаете. Например, суммирование + 1 указателю типа int увеличит его значение на sizeof(int), а не буквально 1, потому что его указатель и логика здесь - это то, что вы хотите следующий объект этого массива.

Например:

int a[] = { 10, 20, 30, 40 }; 
int *b = a; 
printf("%d\n", *b); 
b = b + 1; 
printf("%d\n", *b); 

Он будет:

10 
20 

Поскольку b указывает на целое значение 10, и когда вы подвести 1 к нему, или любая переменная, содержащая целое число, а затем - до следующего значения, 20.

Если вы хотите, чтобы выполнять операции с переменной, хранящейся в b, вы можете использовать:

*b = *b + 3; 

Теперь b тот же указатель, адрес не изменился.Но массив 10, 20, 30, 40 теперь содержит значения 13, 20, 30, 40, так как вы увеличили Элемент b был до от 3.

0

Это действительная вещь, чтобы сделать в C++, и если не почему?

Да. cout << p+y;действительный, как вы можете видеть, пытаясь его скомпилировать. Фактически p+y так действителен, что *(p+y) можно перевести на p[y], который используется в массивах C-стиля (не то, что я предлагаю использовать его на C++).

Действительно не означает, что это действительно имеет смысл или что полученный указатель действителен. Так как p указывает на int, то полученный указатель будет смещением sizeof(int) * 10 от местоположения x. И вы не уверены в том, что там.

+0

не всегда верно (о расположении указателя). Если указатель не ссылается на элемент в границах или один за концом массива, это неопределенное поведение –

3

Что вы делаете в своем фрагменте кода, не преобразует unsigned int в указатель. Вместо этого вы увеличиваете указатель на целочисленное смещение, что является совершенно правильной вещью. Когда вы обращаетесь к индексу массива, вы в основном берете указатель на первый элемент и увеличиваете его на значение целочисленного индекса. Результатом этой операции является другой указатель.

Если р является указателем/массив, следующие две строки эквивалентны и силе (предположим, заостренный к массиву достаточно велико)

p[5] = 1; 
*(p + 5) = 1; 

Для преобразования без знака Int указателю, вы должны использовать литой

unsigned int i = 5; 
char *p = reinterpret_cast<char *>(i); 

Однако это опасно. Как вы знаете, что 5 - действительный адрес?

Указатель представлен в памяти как целое число без знака, адрес. Вы можете сохранить указатель в целое число. Однако вы должны быть осторожны, чтобы целочисленный тип данных был достаточно большим, чтобы удерживать все биты в указателе. Если unsigned int является 32-битным, а указатели - 64-битными, часть информации о адресе будет потеряна.

C++ 11 вводит новый тип uintptr_t, который гарантированно будет достаточно большим, чтобы удерживать указатель. Таким образом, безопасно указывать указатель на uintptr_t и обратно.

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

Однако изменение указателей на целочисленные смещения является полностью допустимым и распространенным.

+0

+1 для воспитания 'uintptr_t' –

Смежные вопросы