2013-06-03 1 views
4

Мне интересно, если у меня есть два указателяЯвляются ли эти два метода для установки указателей равными друг другу одинаковыми?

int *x = (int *)malloc(sizeof(int)); 
int *y; 

и я хочу, чтобы у указать адрес х, является

y = x; 

же, как

y = &*x; 

?

+0

AFAIK, да. * x - это lvalue, & * x - его адрес, который является x. не должно быть никаких побочных эффектов. – Elazar

+1

(Реальный вопрос, конечно, что происходит, когда 'x == NULL') – Elazar

+0

@ Элазар: Это не имеет значения. Это не сбой. – anishsane

ответ

8

Ваш вопрос состоит из двух частей, и это стоит отметить, что они не являются правильными:

Во-первых, вы спросите:

-
y = x;
такие же как
y = & * x;

Поскольку разыменовать (*) и адрес-(&) операторов имеют тот же precedence они будут связываться справа налево, так что

y = &*x; 

такая же, как:

y = &(*x); 

И да, это даст тот же эффект, что и y=x; Теперь, если у вас есть компилятор, совместимый с C, который следует букве закона, это будет не только тот же эффект ctively, он будет быть таким же, это связано с разделом 6.5.3.2 P3 из C Спецификация:

Унарный & оператор дает адрес операнда. Если операнд имеет тип '' type '', то результат имеет тип '' указатель на тип ''.

Если операнд результат унарный * операторной, ни этого оператора, ни оператора & вычисляется и результат, как если бы оба были опущены

Таким образом, компилятор будет видеть как * и & вместе и полностью опустить их.


Во второй половине вашего вопроса вы заявили:

I want y to point to the address of x

Предположительно вы знаете, что это не то, что вы делаете, но вы устанавливаете y, чтобы указать на то же самое адрес вместо x. x, конечно, имеет свой собственный адрес и может быть установлен, но вам понадобится другая переменная int **y = &x;, если x является допустимым значением, подлежащим разыменованию.

+0

и если x равно NULL? – Elazar

+0

@ Elazar - 'при условии, что x является допустимым значением, подлежащим разыменованию', является комментарием, который применяется ко всему ответу. – Mike

+0

Да, но я хочу знать, что произойдет, если x is * not * допустимое значение будет разыменовано. Это безопасно? это UB? – Elazar

4

Это функционально эквивалент. Это фактически «мелкая копия».

Таким образом, следующие задания достижения того же конечного результата:

y=x; 

y=&(*x); 

Однако вторая операция займет больше времени, чтобы выполнить, потому что, а не только прямому назначению, вы выполняете косвенность затем адрес работа. Компилятор может просто оптимизировать это до y=x в любом случае, в зависимости от вашей системы.

Edit:


В афише ниже примечания, если ваш компилятор поддерживает стандарт C, включая 6.5.3.2 P3 стандарта C, это, безусловно, будет оптимизированными, вероятно, на препроцессор до того, как код будет даже скомпилирован.

+1

Вы уверены, что это займет больше времени? Если они действительно эвквивалентны, это не может быть правдой. Для косвенности требуется операнд. – Elazar

+0

«Функционально» эквивалент в том же виде, что и результирующие значения, вывод и т. Д. Это не означает, что они предпримут те же шаги для достижения того же (детерминированного) вывода. Я исхожу из статистики/математического фона, поэтому я стараюсь быть очень конкретным, когда дело доходит до этого :) – DevNull

+1

Итак, какие шаги предпринимаются в псевдо-неоптимизированной сборке? (Конечно, АСТ * не * то же самое.) – Elazar

2

Да, хотя второй выглядит как запись для конкурса обфускации.

2

Да, они такие же, но очень изогнутые.

Вы можете проверить это, выполнив следующие действия:

y = &(*x); 
printf("%p\n", (void*)x); 
printf("%p\n", (void*)y); 
+0

В этом тесте не сказано много. Возможно, это так. – Elazar

+0

Отпечатанный адрес указателя X & Y будет соответствовать, довольно сам пояснительный. – Geoffrey

+1

Да, но вопрос был о языке C, а не о реализации C. – Elazar

1

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

Из-за присутствия &, *x не будет оцениваться вообще. Следовательно, даже если x равно null, это не приведет к сбою/сбою. (Вы можете лучше проверить, используя сборку.)

Когда мы говорим об установке, невозможно вычислить * x (значение) &, затем & (* x) (указатель). Следовательно, компилятор просто вычислит адрес * x, не вычисляя значение * x.

Мы также можем проверить более сложные случаи, например &(a[10]) Это просто переводит на a+10*sizeof(a[0]) в сборку.

Другое доказательство было бы offsetof макрос, как правило, определяется как:

#define offsetof(st, m) ((size_t)(&((st *)0)->m)) 

Здесь, это вычисление &(null_pointer->m), который не вызывает сбой.

+0

Хорошая точка, хотя это и не действительно доказательство. – Elazar

+0

BTW 'размерof' не считается. 'sizeof (printf ("% d ", * (volatile int *) 0))' приведет к 4 или 8 без каких-либо побочных эффектов. – Elazar

+0

Да, sizeof учитывает только тип данных, а не базовые данные. – anishsane

3

Они либо точно такие же по определению, либо почти одинаковые, в зависимости от версии версии стандарта C, с которой вы имеете дело.

В ISO C99 и C11, мы имеем следующую формулировку (со ссылкой на проект N1570 С11) в 6.5.3.2:

Унарный & оператор дает адрес операнда. Если операнд имеет тип «тип», результат имеет тип «указатель на тип». Если операнд не является результатом унаров * оператора, ни того оператор, ни оператор & вычисляется и результат, как если бы оба были опущены, за исключением того, что ограничения на операторы до сих пор применяются и результат не является именующий.

Так Дано:

int *x = /* whatever */; 
int *y; 

эти два точно эквивалентны, даже если x пустой указатель:

y = x; 
y = &*x; 

Без правила специального случая, поведение будет undefined, так как поведение оператора * определяется только в том случае, если его операнд является допустимым непустым указателем. Но так как * никогда не оценивается, он не имеет здесь никакого поведения, определенного или иного. (Тот факт, что, в отличие от x, &*x не именующий здесь не имеет значения.)

И в C89/C90, еще не было добавлены, что правила специального случая, так что поведение &*xявляется не определенно, если x - это указатель null (или иначе недействительный). Большинство компиляторов pre-C99, вероятно, оптимизируют * и &; помните, что характер неопределенного поведения что-то может вести себя так, как вы могли ожидать, что он будет себя вести.

С другой стороны, существует очень реальная разница в поведении любого, кто читает код. Если я вижу y = x;, мое поведение должно думать «О, это обычное назначение указателя». Если я вижу y = &*x;, мое поведение должно подумать: «Зачем ты это написал?» И изменить его на y = x;, если я в состоянии это сделать.

+0

Отличный ответ. И, используя 'y = & * x', очень хороший (и безобидный) способ сказать:« Эй, я новичок, поэтому не знаю, что я делаю. Действуйте осторожно ». – Elazar

-1

Вот небольшая удобная функция, которая может помочь. Не уверен, что вам нужно все «включено».

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <string> 
#include <typeinfo> 
using namespace std; 
int main() { 
int *x = (int *)malloc(sizeof(int)); 
int *y = x; 
int *z = &*x; 

//y = x; 
//z = &*x; 

cout << "x has type: " << typeid(x).name() << '\n' 
     << "y has type: " << typeid(y).name() << '\n' 
     << "z has type: " << typeid(z).name() << '\n' 
     << "values are " << x <<" "<< y << " " << z << '\n'; 
} 

В результате я получаю от этого:

x has type: Pi 
y has type: Pi 
z has type: Pi 
values are 0x1a3a010 0x1a3a010 0x1a3a010 

Ответ то есть, да, методы точно так же, с помощью Ubuntu 14.10, г ++

+2

Не могли бы вы добавить вывод? – rapvelopment

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