Що таке непрозорий вказівник у C?


79

Чи можу я знати використання та логіку концепції непрозорого вказівника в C?



25
Я нічого не зрозумів із вікі-сторінки.
Renjith G

2
Гммм; це питання про C було продубльовано до одного позначеного C ++. Це не ідеально. Існує достатня спільність, що це не є основною проблемою, але C ++ має опції та функції, недоступні для C.
Джонатан Леффлер

Відповіді:


125

Непрозорий вказівник - це той, у якому не розкрито деталей базових даних (із визначення словника: непрозорий: прикметник; неможливо проглянути; не прозорий ).

Наприклад, ви можете оголосити у файлі заголовка (це з мого фактичного коду):

який оголошує тип, pmpiякий є вказівником на непрозору структуру struct pmpi_s , отже, все, що ви оголосите як pmpiнепрозорий вказівник.

Користувачі цієї декларації можуть вільно писати код, наприклад:

не знаючи фактичного "визначення" структури.

Потім, у коді, який знає про визначення (тобто код, що забезпечує функціональність для pmpiобробки, ви можете "визначити" структуру:

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

Більше інформації можна знайти на сторінці Вікіпедії для непрозорих покажчиків.

Основне використання - приховування деталей реалізації від користувачів вашої бібліотеки. Інкапсуляція (незважаючи на те, що скаже вам натовп C ++) існує вже давно :-)

Ви хочете опублікувати у своїй бібліотеці лише таку кількість деталей, щоб користувачі могли ефективно її використовувати, і не більше того. Публікація додаткових даних дає користувачам деталі, на які вони можуть покластися (наприклад, той факт, що змінна розміру szзнаходиться в певному місці в структурі, що може призвести їх до обходу елементів керування та безпосереднього керування ним.

Тоді ви знайдете своїх клієнтів, що гірко скаржаться, коли ви змінюєте внутрішні органи. Без цієї інформації про структуру ваш API обмежується лише тим, що ви надаєте, і ваша свобода дій щодо внутрішніх органів зберігається.


1
Ну, яка користь від цього?
Renjith G

6
Непрозорий вказівник - xyzzyтак. Непрозорий покажчик типу є pmpiі непрозорою структурою є struct pmpi. Основне використання цього полягає в інкапсуляції, можливості приховувати деталі реалізації від користувачів. Я оновлю відповідь детально.
paxdiablo

1
Дякуємо за допомогу. Оцінюємо вашу співпрацю.
Renjith G

2
@VinothKumar, єдине, що користувач повинен зробити з непрозорим вказівником, це отримати його або передати йому функції, які знають про його внутрішні елементи, як fopenі fcloseдля FILE *. Чи FILEсправді непрозорий, залежить від того, що ви знайдете stdio.h- якщо він там повністю задекларований, а не просто тип, подібний до того, що наведено у цій відповіді, користувачі можуть потрапити до внутрішніх органів, тож він непрозорий лише за взаємною згодою :-)
paxdiablo

4
Зауважте, що typedef struct pmpi_s *pmpi;це не ідеально: хтось може припустити, що, наприклад, void f(const pmpi val)не має побічних ефектів на аргументи, які не відповідають дійсності.
Дмитро Григор’єв

10

Непрозорі вказівники використовуються у визначеннях інтерфейсів програмування (API).

Зазвичай вони є вказівниками на неповні типи структур, оголошені як:

Їх мета - надати клієнтській програмі спосіб утримувати посилання на об'єкт, керований API, не розкриваючи нічого про реалізацію цього об'єкта, крім його адреси в пам'яті (самого вказівника).

Клієнт може передавати об'єкт навколо, зберігати його у власних структурах даних і порівнювати два такі покажчики, однакові чи різні, але він не може розмежувати покажчики, щоб заглянути, що знаходиться в об'єкті.

Причиною цього є запобігання тому, щоб клієнтська програма потрапляла в залежність від цих деталей, так що реалізацію можна модернізувати без необхідності перекомпілювати клієнтські програми.

Оскільки непрозорі вказівники набираються, існує хороший показник безпеки типу. Якщо ми маємо:

якщо клієнтська програма змішує порядок аргументів, буде виконана діагностика від компілятора, оскільки a struct gadget *перетворюється на a struct widget *без приведення.

Ось чому ми визначаємо structтипи, які не мають членів; кожна structдекларація з іншим новим тегом вводить новий тип, який не сумісний з раніше оголошеними structтипами.

Що означає для клієнта стати залежним? Припустимо, що a widget_tмає властивості ширини та висоти. Якщо він непрозорий і виглядає так:

тоді клієнт може просто зробити це, щоб отримати ширину та висоту:

тоді як за непрозорої парадигми вона повинна використовувати функції доступу (які не вбудовані):

Зверніть увагу, як widgetавтори використовували shortтип, щоб заощадити місце в структурі, і який піддавався клієнтові непрозорого інтерфейсу. Припустимо, що віджети тепер можуть мати розміри, які не вкладаються, shortі структура повинна змінитися:

Клієнтський код потрібно повторно скомпілювати зараз, щоб підібрати це нове визначення. Залежно від робочого циклу інструментарію та розгортання, навіть може існувати ризик, що цього не буде зроблено: старий клієнтський код намагається використовувати нову бібліотеку і неправильно поводиться, отримуючи доступ до нової структури за допомогою старого макета. Це легко може статися з динамічними бібліотеками. Бібліотека оновлюється, але залежні програми - ні.

Клієнт, який використовує непрозорий інтерфейс, продовжує працювати немодифікованим, тому не потребує перекомпіляції. Він просто викликає нове визначення функцій доступу. Вони знаходяться в бібліотеці віджетів і правильно отримують нові intвведені значення зі структури.

Зверніть увагу, що історично (і до цих пір тут і там) також існувала нечітка практика використання void *типу як непрозорого типу дескриптора:

За цією схемою ви можете зробити це без будь-якої діагностики:

API Microsoft Windows є прикладом системи, в якій ви можете мати її в обох напрямках. За замовчуванням це різні типи дескрипторів, такі як HWND(дескриптор вікна) та HDC(контекст пристрою) void *. Отже, немає типу безпеки; a HWNDможе бути передано там, де HDCочікується a , помилково. Якщо ви зробите це:

тоді ці ручки відображаються на взаємосумісні типи, щоб виявити ці помилки.


2

Непрозорий, як випливає з назви, - це те, чого ми не можемо побачити. Наприклад, деревина непрозора. Непрозорий вказівник - це вказівник, який вказує на структуру даних, вміст якої не піддається на момент її визначення.

Приклад:

Це безпечно призначити NULLдля непрозорого вказівника.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.