Pytanie Odpowiedni typ dla uchwytów w interfejsach C.


Tworzę C api, który ukrywa niektóre funkcje w pliku DLL.

Ponieważ wszystko jest w C ++, większość funkcji działa przeciwko uchwytom, które są mapowane bezpośrednio do tych wskaźników po wewnętrznej stronie API.

Aby uzyskać stopień bezpieczeństwa typu dla tych uchwytów, definiuję je w następujący sposób:

typedef struct MyType1* MyType1Handle;
typedef struct MyType2* MyType2Handle;

Właściwie nie definiuję MyType1 ani MyType2 w żadnym miejscu, ponieważ używam ich tylko jako wskaźników i wykonuję rzutowanie typu wewnątrz api do rzeczywistego typu wskaźnika.

Moim problemem jest to, że korzystając z mojej biblioteki w projekcie clr w visual studio, dostaję to warning: unresolved typeref token (token) for 'type'; image may not run.

http://msdn.microsoft.com/en-us/library/h8027ys9(VS.80).aspx

To nic wielkiego, ponieważ działa, ale wygląda nieprofesjonalnie.

Nie lubię używać void *:

typedef void* MyType1Handle;
typedef void* MyType2Handle;

Dzięki temu można wywołać funkcję, która wymaga MyType1Handle z MyType2Handle, ponieważ są one faktycznie tego samego typu.

Innym podejściem, którego nie chcę używać, jest coś takiego

typedef int MyType1Handle;
typedef int MyType2Handle;

To działałoby dobrze, o ile int i wskaźniki mają ten sam rozmiar, ale nie zawsze tak jest i wydaje się, że nie ma niezawodny sposób na uzyskanie liczby całkowitej o wielkości wskaźnika określonej przez platformę. Ma takie same problemy z bezpieczeństwem, jak pustka *.

Innym podejściem, które próbowałem, było zrobienie tego w ten sposób:

struct MyType1{};
typedef struct MyType1* MyType1Handle;

To nie działało w C, ponieważ puste structs jest nieprawidłowym kodem C. Mógłbym oczywiście rozszerzyć moją strukturę z manekinem, ale wygląda na to, że powinien być lepszy sposób na zrobienie tego.

Moje pytanie sprowadza się zatem do:

Jak ogólnie określasz tego rodzaju typy w najbardziej kompatybilny sposób?


14
2018-05-08 13:21


pochodzenie




Odpowiedzi:


Jeśli spojrzysz na to, jak Microsoft określa jego obsługę winapi (winnt.h), wygląda to tak:

struct HWND__ { int unused; }; typedef struct HWND__ *HWND

w rzeczywistości mają do tego makro:

#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name

więc ... wydaje się, że jest to powszechna praktyka. Niestety nie mogę podać innej sugestii oprócz tej, którą już masz wspomniano, ale mam nadzieję, że i tak ci pomoże.


13
2018-05-08 13:32



Dziękuję za odpowiedź. Wygląda na to, że nie jestem pierwszym, który wpadł na ten problem co najmniej :) - Laserallan
Jedna różnica polega na tym, że w publicznych nagłówkach typ HANDLE odwołuje się do konkretnego typu. Fałszywa struktura jest całkowicie zdefiniowana. Oczywiście definiują one DECLARE_HANDLE inaczej, gdy dołączają te pliki do implementacji. - RBerteig


Użyj nieprzezroczystej struktury. Jest to dobry pomysł w wielu przypadkach przy definiowaniu interfejsu do biblioteki w C: poprawia modułowość, ukrywa niepotrzebne szczegóły

Jak powiedział JamieH, otrzymujesz nieprzezroczystą strukturę deklarując - ale nie definiując - strukturę. Jest całkowicie poprawne posiadanie i przekazywanie wskaźników do nieprzezroczystej struktury do funkcji bibliotek jako argumentów i zwracanie ich jako wartości. Użytkownicy biblioteki nie mogą jednak tworzyć ani modyfikować obiektów nieprzezroczystej struktury, ponieważ jej rozmiar i treść są nieznane.

Biblioteka standardowa C i wiele innych już używa tego podejścia, więc powinno być znane. Przykładem armonicznym jest użycie FILE *: fopen() tworzy i inicjalizuje strukturę i zwraca do niej wskaźnik, fclose() czyści i zwalnia, a wszystkie inne funkcje wejścia / wyjścia otrzymują swój kontekst od przekazanego FILE *.


8
2018-05-12 03:05



Ukrywanie wskaźników w typedefs często wymaga kłopotów (mówiąc o komunikacie o błędzie, który bełkocze coś o wskaźnikach, nawet jeśli twój program ich nie używa lub na odwrót); więc podejście HWND powyżej nie mogę naprawdę polecić; definicja struct-not-exposed działa lepiej. W C ++, ponieważ definicja klasy musi zostać udostępniona, aby rzeczy działały, najlepiej byłoby zastosować podejście "d-pointer". - user502515


Myślę, że możesz po prostu zadeklarować, ale nie zdefiniować struktur źródłowych:

struct MyType1;

typedef struct MyType1 * MyType1Handle;


3
2018-05-09 23:12





Podobny temat: Porównanie uchwytów: puste klasy a niezdefiniowane klasy vs. void *


0
2017-12-25 13:58