2012-04-25 8 views
7

Sto lavorando in C, e ho alcune variabili che non voglio essere globali, ma voglio ottenere e impostare metodi per loro a cui è possibile accedere "Globaly" all'esterno del file. Sono abituato a farlo in Java, ma C è molto diverso in questo modo. Fondamentalmente sto cercando qualcosa che segue questo codice pseudo, ma non sono stato in grado di trovare da nessuna parte con esempi che potrei guardare.C Variabili private Ottieni e imposta metodi

main.c 
#include data.h 
set(b); 

datalog.c 
#include data.h 
get(b); 

data.c 
private int c; 
set(b){ 
    c = b; 
} 
get(c){ 
    return c; 
} 
+0

'C' non ha la nozione di' privato'. Forse provando a guardare le variabili globali 'static'. – RageD

+0

Quindi la mia domanda. Come posso ingannare C? – Reid

+0

Dipende da cosa stai cercando di fare. Dato che 'C' non è OOP (è orientato alla funzione), dovrai lavorare con funzioni e' struct's o variabili globali. – RageD

risposta

10

Si effettua la variabile static. Quando viene effettuata una variabile globale static, il suo ambito è limitato al file corrente.

Un esempio è il seguente:

file: main.c

#include <stdio.h> 

#include "header.h" 

extern int get(); 
extern void set(int); 

int main() 
{ 
    set(10); 
    printf("value = %d \n", get()); 
    set(20); 
    printf("value = %d \n", get()); 
    set(30); 
    printf("value = %d \n", get()); 
    set(40); 
    printf("value = %d \n", get()); 
    return 0; 
} 

file: header.h

#include <stdio.h> 

int get(void); 
void set(int); 

file: intestazione.c

#include "header.h" 

static int value = 0; 

int get(void) 
{ 
    return value; 
} 

void set(int new_value) 
{ 
    value = new_value; 
} 

uscita:

$ gcc -Wall -o main main.c header.h header.c 
$ ./main 
value = 10 
value = 20 
value = 30 
value = 40 
$ 
+1

Non c'è bisogno di dichiarare 'get()' e 'set()' all'inizio di 'main.c'. - Questo è il motivo per cui hai creato l'intestazione in primo luogo. –

+2

Non è necessario includere 'stdio.h' nell'intestazione. - Il codice nell'intestazione non lo usa. –

+1

'header.c' - lol –

2

È possibile digitare:

static int c; 

In questo modo, il ".o" non esportare la variabile "c".

+0

Quindi sarò in grado di accedervi dalle funzioni get e set, ma non direttamente? IE. 'Static' Cambia l'ambito della variabile? – Reid

+1

'static' rende una variabile globale visibile solo all'interno del modulo dichiarato. Ad esempio, se un altro modulo fa 'extern int c', il linker non sarà in grado di trovare "c". – user1202136

7

Se si desidera che le variabili private in c, ci sono un certo numero di tecniche che possono approssimare una variabile privata, ma il linguaggio C in realtà non ha un concetto di "protezione" che si estende a privato, pubblico, protetto (come C++ lo fa).

C mostrerà il nome di qualsiasi variabile (è un requisito in C), quindi è necessario avvicinarsi con l'idea di nascondere le informazioni del tipo della variabile (making dereferenziando abbastanza difficile).

Un trucco è quello definire la variabile come void* con il tipo di variabile reale che è noto in un solo .c modulo.

/* somefile.h */ 

extern void* counter; 

/* somefile.c */ 

#include "somefile.h" 

int actualCounter = 0; 
void* counter = &actualCounter; 

/* otherfile.c */ 

#include "somefile.h" 

// we can see "counter", but we cannot "use" it here; because we don't have access 
// to the real "hidden" type of "int". 

Un metodo migliore è quello di estendere questa idea utilizzando la parola chiave struct, e fare pseudo-metodi, in questo modo

/* person.h */ 

struct s_person; 

typedef Person struct s_person; 

Person* new_Person(char* name); 
void delete_Person(Person* person); 

void Person_setName(Person* person, char* name); 
char* Person_getName(Person* person); 

/* person.c */ 

struct s_person { 
    char* name; 
}; 

Person* new_Person(char* name) { 
    Person* object = (Person*)malloc(sizeof(struct s_person)); 
    // duplicate the string for more security, otherwise constructor 
    // could manipulate the "private" string after construction. 
    object->name = strdup(name); 
    return object; 
} 

void delete_Person(Person* person) { 
    // some implementations pass a Person** to set the reference to 0 
    // this implementation requires that the caller sets his own references to 0 
    free(person->name); 
    free(person); 
} 

void Person_setName(Person* person, char* name) { 
    // free the old 
    free(person->name); 
    // duplicate the new to provide "out of simulated class" modification by malicious 
    // name setter. 
    person->name = strdup(name); 
} 

char* Person_getName(Person* person) { 
    // must return a copy, otherwise one can manipulate name 
    // from reference provided by Person_getName(...); 
    return strdup(person->name); 
} 

/* otherfile.c */ 

#include "Person.h" 

/* Now we can hold Person "simulated objects", but we cannot */ 
/* manipulate their "state" without using the C simulated object */ 
/* methods */ 

int main(int argc, char** argv) { 

    Person* bob = new_Person("bob"); 
    printf("%s\n", Person_getName(bob)); 
    delete_Person(bob); 
    // critical or we hold a pointer to freed memory. 
    bob = 0; 

    return 0; 
} 

Tecniche come questa hanno diverse varianti, uno è quello di avere un "struct pubblico "con un puntatore vuoto * alla" struttura privata ". Uno è quello di includere i "metodi" come puntatori di funzione nella "struttura pubblica" (un passo verso il supporto del polimorfismo), uno è scrivere un sistema di tipo C++ completo e corretto che tenta di risolvere le cose esattamente come farebbe il C++ (gerarchie di classi, polimorfismo, associazione tardiva, occultamento di informazioni, ecc.).

In sostanza, è possibile ottenere un po ' "object-oriented-ness", senza troppo lavoro, ma quando si aggiungono ulteriori funzionalità di -ornamentation, si aggiungerà più codice colla (fino a quando non è molto più semplice utilizzare effettivamente un linguaggio di programmazione orientato agli oggetti).

+1

Corretto: typedef Persona struct s_person; ? Sarebbe: typedef struct s_person Person ;, giusto? –

1

Con il vostro esempio, si può provare a utilizzare alcune struct con queste informazioni. Un struct è come un class con solo pubblico variabili membro (vale a dire senza funzioni). Quindi prendere in considerazione qualcosa come segue

#include <stdio.h> 

typedef struct _somestruct 
{ 
    int c; 
} theStruct; 

int getC(theStruct* obj) 
{ 
    if(obj == NULL) 
    return -1; 
    return obj->c; 
} 

void setC(theStruct* obj, int val) 
{ 
    if(obj == NULL) 
    return; 
    obj->c = val; 
} 

int main() 
{ 
    theStruct myStruct; 
    setC(&myStruct, 5); 
    printf("%d\n", getC(&myStruct)); 
    return 0; 
} 

Come si può vedere, C funziona solo con oggetti e funzioni. Ma per ottenere una variabile globale su tutti i file, prova static int c = 0;

L'esempio sopra è quasi il più vicino possibile ad una convenzione "stile java".

1
static int c; 

int get(void) { 
    return c; 
} 

int set(int n) { 
    c = n; 
}