Zmienna globalna pomiedzy dwoma projektami

Zmienna globalna pomiedzy dwoma projektami
TY
  • Rejestracja:około 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:41
0

Hej,
Pisze w c++ program na studia, mam Visual Studio i projekt A ktory ma referencje do innego projektu B ktory jest biblioteka .lib.

I teraz chce stworzyc zmienna globalna aby funkcji z jednego i drugiego projektu mogly jej uzywac. Dla uproszczenia niech na razie w ogole nie bedzie plikow naglowkowych a deklaracje beda w plikach cpp.

W ktorym projekcie powinna byc definicja takiej funkcji a w ktorym tylko deklaracja tak abym mogl w funkcjach nalezacych do obu projektow sie do nich odnosic?

Z gory dziekuje,
pozdrawiam

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
6

W ktorym projekcie powinna byc definicja takiej funkcji a w ktorym tylko deklaracja tak abym mogl w funkcjach nalezacych do obu projektow sie do nich odnosic?

W żadnym bo to jest jakiś tragiczny pomysł. W ogóle zmienne globalne to słaby pomysł a współdzielenie ich w taki sposób to już zakrawa o szaleństwo. Możesz wyjaśnić co chcesz w ten sposób osiągnąć? Bo na pewno nie idziesz dobrą drogą.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
kaczus
  • Rejestracja:około 10 lat
  • Ostatnio:minuta
  • Lokalizacja:Łódź
  • Postów:1402
1

Tak jak poprzednik napisał, jak masz pomysł na zmienną globalną, znaczy się powinieneś raz jeszcze przemyśleć projekt, bo jest zły. Zmienne globalne winno się używać w wyjątkowych przypadkach.


Ogólnie na prace domowe mam stawki zaporowe. Czasem coś o programowaniu znajdzie się na mojej stronie
TY
  • Rejestracja:około 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:41
0

Chce sie nauczyc pracy pomiedzy projektami i zrozumiec zaleznosci ktore sa miedzy nimi i jak dobrze rozpoznawac takie zaleznosci. bo mam duzo roznych projektow powiazanych ze soba w jednej solucji i mam problem z bledami linkera gdy probuje dolaczac biblioteki z innych projektow i wywolywac z nich funkcje. Moja wiedza jest teraz na poziomie jednego projektu gdzie mam pliki .cpp ktore sa kompilowane do plikow .o, i linkowane statycznie z pojedynczymi bibliotekami .lib wtedy rozumiem co sie dzieje.

Problem mam gdy sprawa sie komplikuje i projektow jest duzo, wszystkie maja zaleznosci miedzy soba. Czesc jest poustawiana jako referencje do innych projektow, czesc jako dependencje, a czesc bibliotek po prostu dodana we wlasciwosciach jako inputy do linkera.

Mam sytuacje taka ze mam referencje do projektu ktory jest libem, a gdy chce uzyc z niego jakiejs zmiennej lokalnej to wysypuje mi sie masa bledow kompilacji. chce zrozumiec czego jest to wynikiem.

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 3 lata
  • Postów:1493
0

Nie znam Visuala, natomiast jak już musisz tworzyć zmienną globalną:
http://stackoverflow.com/questions/496448/how-to-correctly-use-the-extern-keyword-in-c ;)

TY
  • Rejestracja:około 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:41
0

Ale ja wiem jak ją stworzyć w obrębie jednego projektu i kilku plików cpp tylko problem mam z dependencjami. Więc może sprecyzuje moje pytania.

Jeżeli mam dwa projekty i pierwszy z nich tworzy plik binarny .exe a drugi statyczną bibliotekę .lib. I oba te projekty są w jednej solucji to jakie są fizycznie możliwości aby wywołać funkcje albo odnosić się do zmiennych z drugiego projektu w pierwszym projekcie?

Na pewno jednym sposobem jest include pliku nagłówkowego i dodanie tego liba we właściwościach dla pierwszego projektu. Ten sposób zadziała nawet jak bym nie miał źródeł tylko sam plik lib.

A czy to że mam projekty oba w solucji umożliwia jakieś bezpośrednie zlinkowanie plików .o bez pośredniego tworzenia pliku .lib?
W visual studio mogę ustawiać dwie rzeczy: dependencje między projektami w solucji oraz referencje.

Rozumiem to tak że jeżeli ustawię dependencje mojego projektu .exe do projektu biblioteki to on najpierw zbuduje bibliotekę a potem exeka. Jak to jest w przypadku ustawienia referencji?

MY
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 dni
  • Postów:1082
0

@tytrydsdf trochę kombinujesz. Skoro masz plik *.lib to nie ma innej metody aby dodać do innego projektu tego liba wraz z plikiem *.h. Jeśli chcesz łączyć pliki *.o to połącz oba projekty w jeden i nie będziesz miał tego problemu.

Swoją drogą to rozwiązanie z libami jest wygodniejsze ponieważ jednej libki można używać nawet w 100 projektów i nie kompilujesz tego samego kodu 100 razy, tylko jeden tworząc nową wersję *.lib.

Co do samej zmiennej globalnej to zrobienie takiej zmiennej w lib'ce powoduje to, że ona będzie również globalna w pliku exe. Dlatego nie warto z tego rozwiązania korzystać, bo przy większej liczbie projektów łatwo i konflikt nazw.

TY
  • Rejestracja:około 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:41
0
Mr.YaHooo napisał(a):

@tytrydsdf trochę kombinujesz. Skoro masz plik *.lib to nie ma innej metody aby dodać do innego projektu tego liba wraz z plikiem *.h. Jeśli chcesz łączyć pliki *.o to połącz oba projekty w jeden i nie będziesz miał tego problemu.

Na razie chcę tylko użyć zmiennej globalnej i żeby mi to zadziałało. Jak to będę już miał to będę myślał jak się jej pozbyć i zastąpić czymś innym.

Problem mam w tym że jeżeli dodaję tego liba i chcę wywołać jakąś funkcję, to nagle mam masę błędów linkera o nieznalezionych symbolach. W solucji widzę że projekt tego liba zależy od kilku innych projektów. I czy teraz te wszystkie biblioteki które były potrzebne do stworzenia tego liba muszę pododawać również do mojego projektu?

pylaochos
Bo musisz dodać ściężkę i nazwę liba w którym masz te symbole których szuka.
MY
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 dni
  • Postów:1082
1
tytrydsdf napisał(a):

Problem mam w tym że jeżeli dodaję tego liba i chcę wywołać jakąś funkcję, to nagle mam masę błędów linkera o nieznalezionych symbolach. W solucji widzę że projekt tego liba zależy od kilku innych projektów. I czy teraz te wszystkie biblioteki które były potrzebne do stworzenia tego liba muszę pododawać również do mojego projektu?
Ale przecież linker pokazuje Ci dokładnie jakich funkcji/klas nie widzi i Ty wiesz w jakiej libce one są, ja tego nie wiem bo sypiesz ogólnikami bez konkretnych nazw itp. Dla próby dodaj do głównego projektu również liby których używa dołączany do exe'ca lib i się okaże...

pylaochos
  • Rejestracja:ponad 13 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Warszawa
  • Postów:85
0

Hmmm... użyj po prostu wzorca projektowego Singleton. A odradzanie zostawiam innym bo widzę, że mają problemy z tym, że ktoś się uczy O_o

Shalom
Bo uczenie się od początku jak pisać zły kod to jest średni pomysł. Złych nawyków trudno się później pozbyć. Od tego jest właśnie czas nauki zeby uczyć się jak coś robić dobrze. Na jakieś lewe hacki to przyjdzie czas kiedy deadline goni a poprawne rozwiązanie wymagałoby przepisania połowy systemu.
pylaochos
No dobra, ale z drugiej strony jak się pyta ktoś czy jest sama możliwość na zrobienie pewnej rzeczy, a inni odpowiadają "nie rób tak", to programowanie staje się frustrujące. Z resztą na tylu programistów ilu poznałem w pracy odsetek piszący dosyć dobry jest dosyć mały. Myślę, że czasami można pójść drogą po środku typu "słuchaj, nie rób tak bo jest złe bo [], ale jak by co to możesz zrobić to tak[]" nie szerząc jednocześnie spaghetismu.
Shalom
@pylaochos a pomyślałeś że właśnie dlatego jest tak mało ludzi piszących dobry kod -> bo zamiast uczyć się jak dobrze pisać kod to sklejają z błędnych gotowców i potem takie same błędy powielają? ;)
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
1

Masz projekt A, który się buduje do exe. Masz projekt B, który w pewnym sensie rozszerza to exe.

Teraz musisz się zastanowić, w jaki sposób chcesz zbudować projekt B. Czy po prostu jako statycznego liba, czy dll z eksportowanymi klasami, czy klasyczną dll.

Statyczny lib - to już ponoć wiesz.
DLL z eksportowanymi klasami - klasy, które mogą być wykorzystywane w pliku exe, muszą być wyeksportowane. Czyli podczas budowania projektu B te klasy muszą być oznaczone jako eksportowane, a w projekcie A jako importowane. Robi się to za pomocą odpowiedniego makra (w uproszczeniu):

Plik h:

Kopiuj
 
#ifdef PROJECTB_EXPORTS
  #define PROJECTB_API __declspec(dllexport)
#else
  #define PROJECTB_API __declspec(dllimport)
#endif

class PROJECTB_API MojaKlasa
{
//tu normalnie DEKLARUJESZ klasę, jak w typowym pliku h.
}

Następnie w projekcie B dodajesz w ustawieniach projektu dyrektywę PROJECTB_EXPORTS (Visual zazwyczaj doda Ci coś takiego automatycznie, jeśli tworzysz dll).

Dzięki temu projekt B będzie wiedział, że klasę ma eksportować, a projekt A (gdzie includujesz ten plik h) będzie wiedział, że klasę ma importować (bo nie ma nigdzie dyrektywy PROJECTB_EXPORTS).

A potem w projekcie A możesz się posługiwać taką dllką, jakby była zwykłą statyczną biblioteką:

Kopiuj
 
MojaKlasa obj = new MojaKlasa();

Ta metoda ma swoje plusy i minusy. Plusy są takie, że masz dll, którego możesz używać jak liba.
Minusy:

  • nie możesz w klasie jawnie posługiwać się standardową biblioteką. Tzn. nie możesz zrobić czegoś takiego:
Kopiuj
class PROJECTB_API MojaKlasa
{
  void print(const std::wstring & msg);
}

Musisz np.:

Kopiuj
class PROJECTB_API MojaKlasa
{
  void print(const wchar_t * pMsg);
}

Lub jakaś własna obsługa stringa. Nie możesz w taki sposób przekazywać, ponieważ wersje biblioteki standardowej różnią się i dla każdego kompilatora są nieco inne binarnie. Oznacza to, że jeśli projekt B zbudujesz w jednym kompilatorze (np. VisualStudio 2012) i będziesz chciał go używać z poziomu projektu utworzonego w innym kompilatorze (np. VisualStudio 2013), to pojawią się błędy w działaniu związane z pamięcią. W ogóle taki kod chyba nawet nie skompiluje się poprawnie. Tzn. jeśli klasa jest eksportowana, to wszystkie jej składniki też muszą być oznaczone jako eksportowane. Obiekty biblioteki standardowej takie nie są.

Nie wiem też, czy można taką dllkę zastosować bez problemów w innym języku, niech się ktoś wypowie.

Masz jeszcze trzecią możliwość. Klasyczna dllka.
W pliku h umieszczasz deklarację jakiegoś interfejsu.
Umieszczasz też funkcję, która utworzy Ci obiekt tego interfejsu i kolejną, która go zniszczy. W skrócie to mogłoby wyglądać tak:

Kopiuj
class IPrintable
{
  public:
      virtual void PrintMsg(const wchar_t * pMsg) = 0;
      virtual void PrintError(const wchar_t * pMsg) = 0;
};

extern "C" bool __stdcall CreateObject(IPrintable *& pObj);
extern "C" void __stdcall DestroyObject(IPrintable *& pObj);
}
 

Gdzieś w jakimś pliku cpp w projekcie B deklarujesz klasę, która dziedziczy po IPrintable i te funkcje.

Potem w execu jest już trochę trudniej. Musisz załadować taką bibliotekę (LoadLibrary), a następnie odnaleźć określone funkcje (GetProcAddress), itd. Odsyłam tu do netu, bo i tak się dość mocno rozpisałem :) Pamiętaj jednak, że poza takimi deklaracjami, powinieneś zrobić odpowiednie wpisy w pliku def, bo c++ Ci i tak zmieni nazwy funkcji mimo jawnie zastosowanej konwencji (__stdcall).

Generalnie w żadnym z wypadków nie powinieneś eksportować żadnej funkcji, która w argumencie przyjmuje typ z biblioteki standardowej. O tym już pisałem. W ostatnim przypadku pokazałem Ci też, że to projekt B musi zatroszczyć się o stworzenie i zniszczenie eksportowanego obiektu. Z tego samego powodu. Alokacja i dealokacja pamięci różnią się binarnie pomiędzy różnymi kompilatorami.

Teraz jeśli jeden projekt (A) korzysta w jakiś sposób z drugiego (B), to projekt A powinien być zależny od B (dependency), co spowoduje, że projekt B zbuduje się zanim zacznie budować się projekt A. I będziesz też musiał dodać do inputa w projekcie A liba utworzonego na podstawie projektu B(chyba, że projekt B to klasyczna dllka, wtedy linker Cię nie interesuje).

Mam nadzieję, że nie zamotałem za bardzo i wiesz o co chodzi.

MY
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 dni
  • Postów:1082
0

@pylaochos ale zdajesz sobie sprawę z tego, że proponowanie singletona tylko po to aby uniknąć zmiennej globalnej też nie jest dobrym rozwiązaniem? Dla mnie samo użycie singletona powinno być motywowane czymś innym niż niechęć do zmiennych globalnych.

@Juhas całkiem zgrabnie rozpisane różnice. Ja osobiście używam 3 wersji z dynamiczną dll'ką. Daje to największe możliwości. Co do eksportowania metod mających argumenty typu std::string to jest to możliwe, jednak trzeba pilnować aby wszystkie projekty były budowane z użyciem tej samej wersji środowisk, co na dobrą sprawę nie jest jakieś trudne do użycia. Jednak eliminuje wtedy możliwość użycia takiej dll'ki w innym środowisku, nie mówiąc już o innym języku.

pylaochos
Acha, nie od dzisiaj wiem, że singleton to antywzorzec. Aczkolwiek >czasami< jest potrzebny. Ba, wręcz nie zastąpiony. Podsunąłem tylko jedno z rozwiązań, które warto poznać. Motywacja to chyba osobny temat, jeżeli mówimy o tym wątku.
MY
@pylaochos niech Ci będzie. Jednak ja i tak będę się upierał, że o wiele lepszą techniką będzie użycie innej techniki aniżeli export singletonu. Ale to już dłuższa dyskusja.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)