2011-03-20 23 views
6

que definen una estructura en un archivo de cabecera de este modo:¿Cómo hacer que los miembros de struct sean privados?

typedef struct { 
    void *data; 
} point; 

Quiero evitar que otras personas accedan a * de datos directamente, por lo que pensé en declaro la estructura en el archivo .c lugar y usar algo como extern typedef struct point; en el archivo de encabezado. Eso no funciona sin embargo.

¿Cuál es la mejor manera de lograrlo?

+1

Se puede crear un 'something_protected.h' y declarar su material protegido por allí, e incluirlo formar su' .c' archivo así como su archivo "público" '.h'. - Aunque no creo que sea la convención para este problema. Si necesita protección use C++, tiene funciones más avanzadas para cosas como esta. – vbence

+0

Lo que "falta" es la etiqueta struct. Después de su código anterior, hay una definición de estructura sin nombre en el alcance: no puede referirse a ella con 'struct something'; debe referirse a él por su nombre de tipo 'punto'. – pmg

Respuesta

14

En el archivo (público) cabecea:

typedef struct point point; 

En el archivo .c:

struct point 
{ 
    void *data; 
}; 

Tenga en cuenta que los usuarios de su código ya no serán capaces de crear una point en la pila, como el compilador no sabe qué tan grande es. Es posible que deba proporcionar una función point_create() que asigne memoria y devuelva su dirección a la persona que llama.

+2

+1 Si desea este tipo de protección en un lenguaje como C, la pérdida de la asignación de la pila es un precio que simplemente debe pagar. –

+0

Tenga en cuenta que esto realmente no protege los datos, solo ofusca levemente las cosas. No hay nada que impida a alguien decir 'struct pointHack {void * privateData;}' y luego convertir un 'point *' en 'pointHack *' (o incluso en un 'void *' en este caso) y hacer lo que quiera con el 'privateData'. – aroth

+1

Ejemplo extendido en GArray de GLib [garray.h] (http://www.koders.com/c/fid8FB61A2BBE7D60C0F771AB4598CBB478FEF1463D.aspx) [garray.c] (http://www.koders.com/c/fidCCADEC9926A37BB502665981738D6ABE81AAF332.aspx) –

4

Utilice C++


Desde chistes no parecen ser permitidos aquí es la versión C puro. Como señaló otro comentarista si realmente desea proteger su interior de los usuarios de su Api, ha visto y usado muchos de estos Apis. Estas Apis son, p. el modo de usuario de Windows o Linux Apis. Ahí creas objetos kernel a los que nunca tendrás acceso. Los Apis para tratar con objetos kernel usan una construcción sintética llamada handle que no es simplemente un puntero a su propio objeto, sino que es un índice de una matriz donde el kernel ha almacenado los metadatos relevantes para su objeto. Puede usar la misma idea para su Apis también. Aquí, por ejemplo, es una API pública C-Style:

// Public.h 
#include <stdlib.h> 

typedef enum 
{ 
    None = 0, 
    PointType = 1 
} Types; 

typedef int Handle; 

Handle CreateType(Types type); 
int DeleteType(Handle object); 

void IncrementX(Handle point); 
void PrintPoint(Handle point); 

Como se puede ver que tiene métodos genéricos que crean y eliminan los objetos que se definen aquí en una enumeración. Los métodos que usan el objeto necesitarán buscar el manejador de enteros para obtener el objeto de metadatos donde se almacenan los datos reales. Este diseño no es muy eficiente si los objetos que administra son pequeños ya que para cada objeto se necesita un segundo objeto que almacena el tipo de objeto, el valor de manejo y el puntero a los datos reales. pero se obtiene mucho más fuertes garantías de seguridad tales como

  • seguridad Tipo
  • identificadores no válidos son fáciles de encontrar
  • Doble libre es imposible ya que se puede administrar el estado libre en el meta objeto

Un uso típico de la Api podría tener este aspecto:

Handle h = CreateType(PointType); 
IncrementX(h); 
IncrementX(h); 
PrintPoint(h); 
DeleteType(h); 

Un y hay una implementación súper secreta en privado.CPP, donde la matriz de búsqueda de la manija y algunos métodos de ayuda existir:

// Private.C 
#include "stdafx.h" 
#include <stdlib.h> 
#include <Windows.h> // for ZeroMemory 

#include "Public.h" 

typedef struct 
{ 
    LPVOID pData; 
    Types type; 
    Handle handle; 
} HandleInfo; 


typedef struct 
{ 
    int x; 
    int y; 
} Point; 

HandleInfo *pAllocated; 
int HandleBuffer = 0xffff; 
unsigned char bInit = 0; 

HandleInfo *GetFreeHandle() 
{ 
    int i; 

    if(!bInit) 
    { 
     pAllocated = (HandleInfo *) malloc(sizeof(HandleInfo)*HandleBuffer); 
     bInit = 1; 
     ZeroMemory(pAllocated, sizeof(HandleInfo)*HandleBuffer); 
    } 

    for(i=0; i<HandleBuffer; i++) 
    { 
     HandleInfo *pInfo = (pAllocated+i); 
     if(0 == pInfo->handle ) 
     { 
      pInfo->handle = i+1; 
      return pInfo; 
     } 
    } 

    return NULL; 
} 

HandleInfo * GetHandleInfo(Handle h) 
{ 
    if(h <= 0 || h >= HandleBuffer-1) 
    { 
     return NULL; 
    } 

    return (pAllocated+h-1); 
} 

Handle CreateType(Types typeId) 
{ 
    HandleInfo *pInfo; 

    pInfo = GetFreeHandle(); 
    if(NULL == pInfo) 
    { 
     return -1; 
    } 

    pInfo->type = typeId; 
    switch(typeId) 
    { 
     case PointType: 
      pInfo->pData = malloc(sizeof(Point)); 
      ZeroMemory(pInfo->pData, sizeof(Point)); 
     break; 

    } 

    return pInfo->handle; 
} 

int DeleteType(Handle object) 
{ 
    HandleInfo *pInfo = GetHandleInfo(object); 

    if(NULL == pInfo ) 
    { 
     return -1; 
    } 

    if(pInfo->handle != 0) 
    { 
     free(pInfo->pData); 
     pInfo->pData = NULL; 
     pInfo->handle = 0; 
     return 1; 
    } 
    else 
    { 
     return 0; // Handle was already closed 
    } 
} 

void *GetObjectOfCorrectType(Handle object, Types type) 
{ 
    HandleInfo *p = GetHandleInfo(object); 
    if(p == NULL) 
    { 
     return NULL; 
    } 

    if(p->type != type) 
    { 
     return NULL; // handle has wrong object type 
    } 

    return p->pData; 
} 

void IncrementX(Handle point) 
{ 
    Point *pPoint = (Point *) GetObjectOfCorrectType(point, PointType); 
    if(pPoint == NULL) 
    { 
     return; 
    } 

    pPoint->x++; 
} 

void PrintPoint(Handle point) 
{ 
    Point *pPoint = (Point *) GetObjectOfCorrectType(point, PointType); 
    if(pPoint == NULL) 
    { 
     return; 
    } 

    printf("Point has x: %d y: %d", pPoint->x, pPoint->y); 
} 

Suyo, Alois Kraus

+0

La pregunta está etiquetada C, por lo que una respuesta en C++ no es relevante aquí. – dreamlax

+1

¿Has leído mi respuesta hasta el final? –

+0

Sí, leí su respuesta, pero eso no cambia mi afirmación. La pregunta tiene una etiqueta C, por lo que C++ es irrelevante aquí. ¿Por qué no también también proporciona técnicas Java, Objective-C y C#? Porque no son relevantes! – dreamlax

0

Puede tener encabezado pública independiente y archivos de cabecera privadas. Algunas bibliotecas tienen convenciones para esto:

  • Xt (X11) ->header.h y headerP.h, por ejemplo: X11/Vendor.h vs X11/VendorP.h
  • Qt ->header.h vs private/header_p.h, por ejemplo: qapplication.h vs private/qapplication_p.h
2
typedef struct { 
    /* private members; don't access directly */ 
    void *data; 
} point; 
0

Si no desea utilizar el método de declaración (porque desea que el usuario de la biblioteca acceda a otros miembros de su estructura, por ejemplo) es una convención t o anteponer miembro privado con un guión, como esto:

typedef struct { 
    void * _data; 
} point; 

supuesto, la gente todavía se podía acceder _data si ellos realmente quieren (al igual que las personas pueden acceder a los datos privados en C++ mediante la adición de un #define private public antes de su incluye), pero esa es su propia responsabilidad; al menos ha indicado que no deberían hacer eso si quieren que su biblioteca se comporte como debería.

0

Utilizo este enfoque para permitir que el cliente aloje la instancia del módulo en su APILAMIENTO.

struct module_private { 
    int data; 
} 

typedef uint8_t module_t [sizeof (struct module_private) ]; 

El cliente podrá ver el contenido de la estructura privada, pero no acceder a ella sin realizar un reparto que no debería.

+1

No use esto. Causará errores de alineación. –

0

utilizar la siguiente solución:

#include <stdio.h> 

#define C_PRIVATE(T)  struct T##private { 
#define C_PRIVATE_END  } private; 

#define C_PRIV(x)   ((x).private) 
#define C_PRIV_REF(x)  (&(x)->private) 

struct T { 
    int a; 

C_PRIVATE(T) 
    int x; 
C_PRIVATE_END 
}; 

int main() 
{ 
    struct T t; 
    struct T *tref = &t; 

    t.a = 1; 
    C_PRIV(t).x = 2; 

    printf("t.a = %d\nt.x = %d\n", t.a, C_PRIV(t).x); 

    tref->a = 3; 
    C_PRIV_REF(tref)->x = 4; 

    printf("tref->a = %d\ntref->x = %d\n", tref->a, C_PRIV_REF(tref)->x); 

    return 0; 
} 

El resultado es:

t.a = 1 
t.x = 2 
tref->a = 3 
tref->x = 4 
Cuestiones relacionadas