2013-11-02 1 views
1

Is -> делать то же самое в C как . в Java/C#?Является ли x -> y тем же в c, что и x.y в C#/java?

В Java/C# вы получаете доступ к элементам внутри структуры через оператор ..

Мне кажется, что d_name внутри dir и его время доступа в качестве элемента внутри dir

DIR *d; 
struct dirent *dir; 
d = opendir("."); // get current directory 
if (d) 
{ 
    while ((dir = readdir(d)) != NULL) 
    { 
    // whilst item exists 
    printf("%s\n", dir -> d_name); 
    } 
closedir(d); 
} 

Если это не так, то я что-то не хватает, и я хотел бы простое объяснение, если это возможно.

+1

Мне бы очень хотелось сказать, что это одно и то же, но это похоже на то, что происходит * неявное * «разыменование», которое происходит. – user2864740

ответ

4

В смутном смысле, да. Java не имеет указателей, а понятие объектов передается по значению; в сущности, все объекты хранятся и передаются по ссылке, а связанная память освобождается сборщиком мусора при неиспользовании.

+0

Спасибо, так что это почти так просто, 'd_name' находится внутри этой' dir' структуры. – Joseph

+0

Закрыть, но 'dir' является указателем на структуру, которая разыменована (за ней) до того, как элемент' d_name' будет извлечен. 'dir-> d_name' эквивалентно' (* dir) .d_name'. –

+0

Спасибо, мне нужно сделать гораздо больше чтения в * разыменования * указателей, чтобы действительно понять. Я все еще не совсем понимаю значение * разыменования *. Но ваш ответ прояснил, что происходит в вышеуказанном коде, так что спасибо вам большое! – Joseph

1

Имейте в виду разницу между структурой и указателем на структуру.

Предположим, что 32-битный компилятор.

Давайте создадим-структуру:

struct point_i { 
    int x; 
    int y; 
}; 

Эта структура имеет два элемента Int. Каждое целое число имеет размер 4 байта, поэтому размер структуры составляет восемь байтов.

Затем используйте:-структуру

strut point_i my_point;  // 8 bytes allocated, lets assume that they 
           // are located at address 0x10000000. 
my_point.y = 10;    

Когда вы сделаете это, то компилятор знает, где находится my_point и его размер, и он также знает, где член y является относительно структуры. Так он компилирует (очень грубо) на что-то вроде:

MOV [0x10000004], 10  ;; Notice that its 0x10000000 + 4. 
         ;; The first four bytes are X so we skip them 
         ;; to get to Y and put 10 in that memory address. 

С другой стороны, если у вас есть указатель:

strut point_i *another_point;  // 4 bytes allocated, the pointer size. 
            // Let's assume in 0x20000000. 

another_point = get_random_point(); // Get an address to some random point. 

another_point->y = 10;    // You have to use -> to reference the member 
            // because you are not dealing with an struct 
            // anymore but a *pointer* to said struct. 

И поскольку компилятор не имеет ни малейшего представления, что решения вы собираетесь поставить в этом указателе он должен генерировать код, который немного отличается.

MOV EBX, [0x20000000]  ;; 0x20000000 has your pointer. So we fetch it. 
MOV [EBX+4], 10   ;; Dereference the pointer and put 10 in Y. 
          ;; You can see that we now have two memory references, 
          ;; one to get the pointer and another to get where it 
          ;; points to. So it is a layer of indirection. 

Обратите внимание, что это очень упрощенный вид на мир. Компилятор/компоновщик и операционная система разрешают адреса памяти в ваших программах. Но он должен прояснить, что происходит за кулисами. Разрушение указателя является основной частью C.

+0

_Notice, что это очень упрощенный взгляд на мир ... Действительно? :) – ryyker

+0

Ну, может быть, не * так * просто :) –

0

Переменные типа класса в .NET и Java содержат ссылки, поведение которых аналогично поведению указателя malloc'ed в C, за исключением того, что C допускает арифметику и преобразования между указателями и целые числа, тогда как ссылки не допускают такой арифметики и преобразований. Если o содержит ссылку на объект класс С с полем f, o.f в C# или Java, примерно эквивалентен o->f в С.

Методов экземпляра принимают подразумеваемый параметр, который гарантированно содержать ссылку на экземпляр соответствующего типа. Если im является не виртуальным методом o, то o.im(whatever) эквивалентен C_im(o, whatever);.Если vm является виртуальным членом, система определит внутренний метод, который возвращает адрес реализации, применимый к данному экземпляру. Таким образом, o.vm(whatever) эквивалентно C_get_vm(o)(o, whatever);

структур в C#, ведут себя более подобных структур в С. доступа Структура поля использует тот же . маркер как доступ полей классов, но если s представляет собой структуру типа S с полем f, то s.f в C# похож на s.f в C. Методы экземпляра вызываются путем передачи «byref» в экземпляр объекта, так что будет эквивалентен S_im(&s, whatever);. Обратите внимание, что операции с переменной типа структуры будут действовать на самой переменной, в отличие от операций над переменной типа класса, которая (как и для токена C ->) будет выполняться над чем-то, к чему эта переменная содержит ссылку.

PS - Мне не нравится решение использовать C# ., а не -> для доступа к классу или для вызова функций класса, передавая ссылку на объект, содержащуюся в переменной. Я предпочел бы, чтобы foo.whatever последовательно ссылался на или сам изменил foo, а foo->whatever постоянно ссылается или модифицирует вещь, к которой относится ссылка foo. Даже с объектами класса могут быть реализованы не виртуальные методы для передачи byref переменной, такой, например, someString.Append(x); был бы эквивалентен String_Append(ref x); и мог бы изменить то, что удерживает переменная someString (например, указывая на другой экземпляр String). Впрочем, поздно.

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