Array
(
)

Variavel Global

Docdoc
   - 09 dez 2007

Compilador BDS2006 C/C++

Sou um cara do Delphi toda a minha vida. traduzi algumas livrarias do C/C++ para o pascal, mas nunca fiz nada de aprofundado em C/C++.

No momento estou criando uma gerenciador de base de dados e pensei que o C fosse a escolha ideal pois supostamente daria aqueles microlésimos de segundos a mais nas rotinas críticas, mas estou com um problema tão básico que emperra o desenvolvimento do software. O problema se chama VARIÁVEL GLOBAL !!! *************

Na unidade DB.H está descriminado:

#Código


struct CDB {
char szNome[255];
WORD wTables
char Ativo;
}

struct CDB DB;


O problema é que eu consigo acessar a variável DB na unidade DB.C sem problemas, mas quando ela é referenciada em outra unidade, como por exemplo em , TABLE.C, já os dados que estavam nela (variavel) desaparecem, por exemplo:

#Código

DB.C

#include "db.h"

void fun()
{
db.Ativo = 1
}

Agora, vem isso em:

#Código

TABLE.C

include "db.h"

void Outrofun()
{
char Ativo;

Ativo = DB:Ativo; //aqui o campo DB.Ativo já não esta com o valor 1
// mas sim 0, como se nunca tivesse sido setado
}

Qdo eu vejo no watch list do o valor da variavel DB, o compilador mostra o erro E2451 - Undefined symbol ´DB´.

Porra ! Claro que o simbolo está definido, tanto é que o programa compila e roda normalmente, mas os valores dos campos é que são simplesmente apagados qdo a variavel é referenciada em outra unidade.

POR FAVOR ALGUMA AJUDA NISSO ???


Docdoc
   - 09 dez 2007

**** linguagem cheia de artimanhas, por isso que no Delphi qdo ja tamos escrevendo o final os caras de c ainda tão no Hello World.

A solução

#Código


typedef struct {
char Nome[MAX_PATH];
WORD wTables;
STRING* szTables;
BOOL Active;
} TDB;

TDB DB;



Massuda
   - 10 dez 2007

Por favor, leia as :arrow: [url=http://forum.devmedia.com.br/viewtopic.php?t=6689]Regras do forum[/url], em especial o item 1.b.

A grande maioria das linguagens tem variáveis globais. Delphi tem, por exemplo, Application, Screen e, infelizmente, todo form que você cria.
Citação:
Na unidade DB.H está descriminado:

#Código


struct CDB {
char szNome[255];
WORD wTables
char Ativo;
}

struct CDB DB;
Como você declarou a variável num .H, uma instancia da variável será criada em cada arquivo que incluir esse .H. Outro problema é que C faz distinção de maiuscula/minuscula, de modo que db, dB, Db e DB são símbolos diferentes.

O correto é escreve em DB.H..#Código
extern struct CDB DB;
...assim todo módulo que incluir o .H saberá que DB é uma variável global externa (implementada em algum outro módulo e declarar em (possivelmente) DB.C...#Código
struct CDB DB;



Docdoc
   - 13 dez 2007

Massuda, valeu pela resposta, mas...

Sei que a linguagem é case sensitive, o erro ai no código é só de digitação, mesmo porque se vc trocar DB por db, o código já não compila.

O que se passa é que o modificador extern não compila, pois estou tentanto fazer o programa em C, penso que extern só funciona em C++, pelo menos não tem compilado com essa directiva .

A solução acabou sendo etiquetar a estrutura dessa forma:

#Código


typedef struct _TDB {
BOOL Active;
WORD wTables;
char szNome[MAX_PATH];
STRING* szTables;
} TDB, *PDB;

TDB DB;


Assim já posso acessar a tal variável DB em outra unidade e com os dados ja setados. Mas surgiu um outro problema do c****** (caramba) !

O que se passa é que para se copiar o string szNome para outra vairável tem sido impossível, ora veja o código:


Citação:


void fool()
{
char szDest[MAX_PATH];
char *pfonte;
char *pdest;

pfonte = DB.szNome;
pDest = szDest;

//eu tentei estas formas, uma de cada vez, compilam mas não
//funcionam. O szDest continua sem os dados

strcpy (szDest, DB.szNome); //<--não funciona
strcat (szDest, DB.szNome); //<--não funciona
while(*pfonte != ´\0´) *pdest++ = *pfonte++; //<--não funciona

}


Agradeço a qualquer ajuda que me possa dar.


Massuda
   - 13 dez 2007


Citação:
O que se passa é que o modificador extern não compila, pois estou tentanto fazer o programa em C, penso que extern só funciona em C++, pelo menos não tem compilado com essa directiva .
extern funciona em C e é parte da especificação ISO C90.

Este pequeno exemplo simplificado compila e funciona sem problemas usando o compilador C/C++ que vem com o C Builder 5.#Código

/* --- DB.H --- */

#include <stdlib.h>

typedef struct {
char nome[80];
} TDB, *PDB;

extern TDB DB;

/* --- DB.C --- */

include "db.h"

TDB DB;

/* --- foo.c --- */

include <stdio.h>
include <string.h>
include "db.h"

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

strcpy(DB.nome, argv[0]);
printf("DB.nome = \"¬s\"\n", DB.nome);

return(0);
}



Massuda
   - 13 dez 2007

Um exemplo (acho) melhor...#Código

/* --- DB.H --- */ 

#include <stdlib.h>

typedef struct {
char nome[80];
} TDB, *PDB;

extern TDB DB;

void IniciarDB(char *ANome);

/* --- DB.C --- */

include <string.h>
include <mem.h>
include "db.h"

TDB DB;

void IniciarDB(char *ANome) {

memset(&DB, 0, sizeof(DB));
strcpy(DB.nome, ANome);
}

/* --- foo.c --- */

include <stdio.h>
include "db.h"

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

IniciarDB(argv[0]);
printf("DB.nome = \"¬s\"\n", DB.nome);

return(0);
}



Docdoc
   - 13 dez 2007

Massuda, novamente obrigado pela resposta.

Com a directiva extern estou tendo a seguinte mensagem de erro:


Citação:
[Linker Error] Error: Unresolved external ´_DB´ referenced from C:\TOOLS\CODE\C++\DOCDB\TABLE.OBJ


O compilador é o da Borland no produto BDS2006.

O outro problema é ainda mais bizarro, principalmente pra mim que venho do Delphi, ou seja, qdo tento copiar o string da estrutura para uma variavel de escopo local, nada acontece.

No código abaixo a variavel szLocal não recebe os dados do campo da estrura DB.szNome, não sei explicar isso a não ser por bug no compilador :(

#Código



char szLocal[MAX_PATH];

strcpy(szLoca, DB.szNome);



Vou tentar fazer mais alterações, mas se vocÊs tiverem alguma idéia do que tá acontecendo, agradeço ajuda.


Docdoc
   - 13 dez 2007

Caro Massuda, salve:

Reparei que no exemplo que você colocou ai em cima a variável DB foi definida na unidade DB.C, se foi assim mesmo ela só será global para a unidade onde está inserida, o restante do programa não a consegue ´enxergar´, não é mesmo ???

abraços


Massuda
   - 14 dez 2007


Citação:
...se foi assim mesmo ela só será global para a unidade onde está inserida, o restante do programa não a consegue ´enxergar´, não é mesmo ???
Isso não acontece por causa do ´extern TDB DB´ que tem em DB.H. Essa linha diz a qualquer módulo que inclua esse .H que ´existe uma variável DB do tipo TDB que foi implementada em algum outro módulo´.

A variável global DB seria visível apenas em DB.C se ela tivesse sido declarada como static...#Código

static TDB DB;
...nesse caso, toda a linkagem falharia porque o símbolo DB não será encontrado.


Docdoc
   - 14 dez 2007

Caro Massuda, resumindo e concluindo.

a clausula extern eu utilizo quando quero declarar uma variável de uma unidade em outra, por exemplo.

A variável int i foi declarada na unidade FUN.H, ok ?

Para utiliza-la em outra unidade tenho que declara-la novamente, nessa nova unidade, por exemplo em OUTRAUNIT.C, como extern int i, pois ai eu digo a unidade OUTRAUNIT.C que a variavel int i faz parte de fora dessa mesmo unidade, ok ???

Bem mas meu grande problema não tem sido isso, pois já está resolvido, já sei como declarar uma estrutura global, na minha solução passou por etiquetar a estrutura, na verdade o que não consigo copiar os dados da estrutura em outras variáveis locais, no caso concreto :

#Código




void fool()
{
char szDest[MAX_PATH];
char *pfonte;
char *pdest;

pfonte = DB.szNome;
pDest = szDest;

//eu tentei estas formas, uma de cada vez, compilam mas não
//funcionam. O szDest continua sem os dados

strcpy (szDest, DB.szNome); //<--não funciona
strcat (szDest, DB.szNome); //<--não funciona
while(*pfonte != ´\0´) *pdest++ = *pfonte++; //<--não funciona

}


Se voce tem alguma luz sobre essa aberração eu seria eternamente grato


Massuda
   - 17 dez 2007

Mostre como voce declarou a variável DB. Em algum lugar do seu projeto (provavelmente em um arquivo .C) DB deve estar declarado sem o extern.

O etiquetamento que você fala não tem relação com variável global.

Explique melhor o que você quer dizer com ´não funciona´.


Docdoc
   - 17 dez 2007


Citação:
Mostre como voce declarou a variável DB. Em algum lugar do seu projeto (provavelmente em um arquivo .C) DB deve estar declarado sem o extern.

O etiquetamento que você fala não tem relação com variável global.

Explique melhor o que você quer dizer com ´não funciona´.





Ok, então aqui vai o bicho:


#Código



//unidade db.h

#pragma once
ifndef DB_H
define DB_H

include <windows.h>
include "estruturas.h"

typedef struct _TDB {
BOOL Active;
WORD wTables;
char szNome[MAX_PATH];
STRING* szTables;
} TDB, *PDB;

TDB DB;

endif


Agora na unidade table.c

#Código


include "table.h"
#include "DB.h"

include <windows.h>
include <io.h>
include <stdio.h>
include <dir.h>
include <fcntl.h>
include <string.h>
include <malloc.h>
include <sys\stat.h>
include <stdio.h>
include <string.h>

boolean WINAPI OpenTable(STRING name)
{
char path[MAX_PATH];
FILE *file;

// é aqui QUE NÃO FUNCIONA, o campo de DB.szNome não é copiado para path, simplesmente não copia, mas quando fazemos um breakpoint aqui, vemos que DB.szNome está correctamente setado para o caminho do diretorio onde está a tabla a abrir.

strcpy(path, DB.szNome);

//já as próximas instruções funcionam bem, o que significa que path acaba recebendo o valor do parâmetro name e depois a extensão do arquivo ".db"

strcat(path, name);
strcat(path, ".db");

f = open(path, O_RDONLY | O_BINARY , S_IREAD | S_IWRITE);
if (f==-1) {return false;};

//rotina de leitura do arquivo

close(f);

return true;
};


O Mais interessante é que tudo compila na maior ser problemas. A lógica está correcta mas algo falha redondamente, não consigo perceber o que é.

Obrigado pelas ajudas


Massuda
   - 17 dez 2007

Do jeito que está feito, sem extern, o compilador enxerga assim seu fonte table.c...#Código

#include "table.h"

//unidade db.h

pragma once
ifndef DB_H
define DB_H

include <windows.h>
include "estruturas.h"

typedef struct _TDB {
BOOL Active;
WORD wTables;
char szNome[MAX_PATH];
STRING* szTables;
} TDB, *PDB;

TDB DB;

endif


include <windows.h>
include <io.h>
include <stdio.h>
include <dir.h>
include <fcntl.h>
include <string.h>
include <malloc.h>
include <sys\stat.h>
include <stdio.h>
include <string.h>

boolean WINAPI OpenTable(STRING name)
{
char path[MAX_PATH];
FILE *file;

// é aqui QUE NÃO FUNCIONA, o campo de DB.szNome não é copiado para path, simplesmente não copia, mas quando fazemos um breakpoint aqui, vemos que DB.szNome está correctamente setado para o caminho do diretorio onde está a tabla a abrir.

strcpy(path, DB.szNome);
...
...de modo que DB é uma variável global de table.c visível apenas dentro de table.c; não sei o que o debugger está te mostrando, mas possivelmente é um DB declarado em outro módulo, possivelmente o módulo onde vc fez a inicialização de DB.


Docdoc
   - 18 dez 2007

Po, Massuda, agora é que tô louco !

A variavel DB nunca foi declarada em table.c, somente em db.h. Só existe uma variável DB no programa todo.

Em todo o programa o debugger mostra a variável devidamente setada no caminho do diretorio onde contem a tabela, o que se passa é que essee valor não consigo passar pra variável local, sinistro ! Porém já consigo copiar das variáveis locais pra esta variável DB

Vai entender !


Massuda
   - 18 dez 2007

Não sei como é seu programa todo mas...
Citação:
A variavel DB nunca foi declarada em table.c, somente em db.h. Só existe uma variável DB no programa todo.
...existe uma variável DB em cada ´unidade´ que incluir o arquivo DB.H.


Massuda
   - 18 dez 2007


Citação:
...existe uma variável DB em cada ´unidade´ que incluir o arquivo DB.H.
Se estiver mesmo acontecendo isso, o linker deve(ria) gerar um warning do tipo...
Citação:
Warning: Public symbol ´_DB´ defined in both module blablabla.OBJ and foobar.OBJ
...o que indica que a mesma variável publica foi definida em mais de um módulo.


Docdoc
   - 19 dez 2007

:D[size=18:132882bb9e]EUREKA !!! [/size:132882bb9e]:D

[size=18:132882bb9e]ATÉ QUE ENFIM A SOLUÇÃO[/size:132882bb9e]

Antes de mais quero agradecer ao Massuda pela ajuda.

Bem, se vc´s se lembram do problema...eu tinha uma variável global que era uma estrutura e que não conseguia copiar seus dados para outras variáveis locais dentro das funções. Pois bem, agora já consigo e porquê ?

Quando declarei a variável TDB DB fí-lo em db.h e me causou todos esses transtornos, porém ao declará-la em db.c, tudo acabou por se acertar, ou seja, a variável global passou a ser copiável para outras variáveis locais, ou seja, a variável somente esta totalmente acessível quando declarada em db.c.

Quando ela estava declarada em db.h o processador aceitava a compilação mas não permitia a cópia, acredito ser isso um bug.

Bem, já sabemos o que aconteceu.

Agora alguém pode me explicar por quê é assim ?