Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Parametr szablonu będący adresem jakiejś (konkretnej) komórki w pamięci.

Ostatnio zmodyfikowano 2012-10-14 13:46
Autor Wiadomość
cyklopek11
Temat założony przez niniejszego użytkownika
[C++] Parametr szablonu będący adresem jakiejś (konkretnej) komórki w pamięci.
» 2012-10-06 15:58:02
Na wstępie zaznaczam, że nie chodzi mi o : parametr szablonu będący adresem
obiektu tylko adresem jakiejś (konkretnej) komórki pamięci. Utknąłem w
miejscu gdzie Grębosz (Pasja c++, I tom, wyd. trzecie poprawione, str. 157) pisze, że:

"Parametrem szablonu klas może być adres jakiejś komórki pamięci. Możemy
sobie przecież wyobrazić szablon klas,  które mają zająć się konkretnymi
miejscami w pamięci. Adres takiego miejsca można uczynić parametrem
szablonu.Taki adres może opisywać miejsce w pamięci, które jest buforem do
pracy (np. z ekranem IBM PC) ... Oto przykład takiego szablonu:"
C/C++
template < void * wsk >
class oliver
{
public:
    // ... niewazne teraz szczegoly
}

Do utworzenia obiektu takiej klasy korzysta przy tym z niestandardowego
makra MK_FP zdefiniowanego w niestandardowym nagłówku:
<i86.h>, który korzysta również z nagłówka <_comdef.h>.
Mniejsza z tym,można je zdobyć w głębinach internetu. Tak czy siak intuicyjnie takie makro będzie "przerabiało" podane dane adresowe (segment, offset) na liczbę
unsigned int. I też tak robi.
Problem w tym, że kompilator nie dopuszcza do takiego utworzenia zmiennej:

C/C++
oliver < Makro_Ktore_Zwraca_Unsigned_Int > var;

No i nie ma się czemu dziwić, parametrem szablonu ma być void * a jest unsigned int.

No dobra, zatem trzeba przerzutować tę wartość na void * ale takie coś:

C/C++
oliver < reinterpret_cast < void *>( Makro_Ktore_Zwraca_Unsigned_Int ) > var;
wywala błąd:

error: a cast to a type other than an integral or enumeration type cannot
appear in a constant-expression

Zgadzam się oczywiście z kompilatorem :-)

Dalej autor pisze, że takie coś jest niepoprawne:

C/C++
char znak;
void * wsk = & znak;
oliver < wsk > xx; // blad - wsk nie jest stala

Co jest oczywiście ok.

Próba przekazania do szablonu jakiegokolwiek wskaźnika  void * znanego w
trakcie kompilacji też nie działa:

error: 'wskazniczek' is not a valid template argument because
'wskazniczek' is a variable, not the address of a variable.

Próba przekazania do szablonu:
C/C++
void * const wskaznik // zasieg globalny
przy
C/C++
int main()
{
    ...
    oliver < wskaznik > var;
    ...
}
generuje błąd:

error: 'wskaznik' cannot appear in a constant-expression

Próba przekazania do szablonu znanego w trakcie kompilacji wskaznika void * ze słowami kluczowymi (const, volatile, extern) we wszystkich możliwych, poprawnych kombinacjach też nie przechodzi.
Jeśli próbuję zrobić coś takiego:
C/C++
const unsigned int adres = 0x400000; // zasieg globalny

int main()
{
    ...
    oliver <& adres > ekr;
    ...
}
to dostaję zachęcający błąd:

error: '& adres' is not a valid template argument of type 'void*' because 'adres' does not have external linkage

Dodaje więc extern:
C/C++
extern const unsigned int adres = 0x400000; // zasieg globalny
//wczesniejszy szablon

int main()
{
    ...
    oliver <& adres > ekr;
    ...
}

i niestety dostaję błąd:

error: could not convert template argument '& adres' to 'void*'
Czyli ciąg dalszy zabawy w berka :-(
 
Ktoś może pomyśleć, że stwarzam sztuczny problem. Otóż nie, piszę klasę do
obsługi plików PE Windowsa i "zdobycie" adresu w przestrzeni wirtualnej
procesu o odpowiednim atrybucie dostępu to pikuś. W celu przećwiczenia szablonów chciałem tego użyć. I tu jest problem. I nie chodzi mi już o to, że tego potrzebuje bo napisałem już bez użycia szablonów to co chciałem ale zaskoczenie i ciekawość pozostała.
Stąd moje pytanie czy:
Parametrem szablonu może być adres jakiejś (konkretnej) komórki w pamięci (jak poinformować o tym kompilator) czy też nie i jest to błąd w książce ???
P-66166
Admixior
» 2012-10-06 16:14:06
C/C++
template < void * typ > class tescik
{
    void * const wsk;
public:
    tescik()
        : wsk( typ )
    { }
};

int main()
{
    tescik <( void * ) 0x0400000 > empty; //podajesz ogólnie znany adres
}

PS. nie wiem po co jakieś Make Far Pointer (MK_FP) skoro przecież to nie jest nic jak rzutowanie (i ew. dodanie)
#define MK_FP(adres,offset)   ((void*)adres+offset)

//edit:
jak dasz
C/C++
const unsigned int adres = 0x400000;
oliver <& adres > ekr;
to się nie dziw że nie działa. Przecież dajesz nie-stały adres na stos do obiektu "adres".
Chyba chodziło o:
C/C++
const unsigned int adres = 0x400000;
oliver <( coid * ) adres > ekr;
i tak bedzie działać.
P-66168
cyklopek11
Temat założony przez niniejszego użytkownika
» 2012-10-06 19:54:46
Zapomniałem napisać, że wszystkie zmienne "adres" są globalne do testów.
Twoja propozycja:

C/C++
const unsigned int adres = 0x400000; // zasieg globalny

int main()
{
    ...
    oliver <( void * ) adres > ekr;
    ...
}

... też nie działa :-(
P-66202
DejaVu
» 2012-10-06 21:17:48
Jeżeli chcesz zrobić coś takiego to znaczy, że zarówno źle zaprojektowałeś kod, jak i nie rozumiesz idei szablonów. Cel, który chcesz uzyskać można osiągnąć za pomocą zwykłej klasy:
C/C++
class CKlasa
{
public:
    CKlasa( void * arg )
        : x( arg )
    { }
private:
   
    void * x;
};

int main()
{
    CKlasa klasa(( void * ) 0x12345678 );
    return 0;
}
P-66221
DejaVu
» 2012-10-06 21:20:00
Dodam, że C++11 umożliwia przekazywanie wartości zmiennych do szablonów pod warunkiem, że są to constexpr (http://cpp0x.pl/dokumentacja/standard-C++11/constexpr/1096). Szablony są w trakcie kompilacji rozwijane do postaci klasy, a więc niemożliwe jest wygenerowanie kodu dla szablonu, którego parametry nie są znane w chwili jego kompilacji.
P-66222
cyklopek11
Temat założony przez niniejszego użytkownika
» 2012-10-06 21:21:11
Pisałem już w pierwszym poście, że teraz to już ciekawość mną kieruje ...

(wiem to trochę upierdliwe ale jak coś mi nie gra to muszę za wszelką cenę dowiedzieć się dlaczego - tak już mam :-)
P-66223
DejaVu
» 2012-10-06 21:23:13
@up: wybacz, nie czytałem pierwszego posta :P W zasadzie to prawie niczego nie czytałem :P
P-66224
cyklopek11
Temat założony przez niniejszego użytkownika
» 2012-10-14 13:46:40
Przedstawiam wyniki moich badań i poszukiwań związanych z tematem.
Przeszukałem wiele for internetowych, dokumentów związanych ze standardem c++, książki (również Pana Bjarne Stroustrup-a), aż wreszcie wykonałem praktyczne testy na innych kompilatorach niż gcc (zawarty w Code::Blocks).
Moim zdaniem różne kompilatory dla szablonów inaczej interpretują: "stała znana w czasie kompilacji".
I tak  gcc (z Code::Blocks 10.05 niezaktualizowana) stwierdza, że powyższe kody są nieprawidłowe. Aczkolwiek skoro przechodzi linijka definicji szablonu:
C/C++
template < void * wsk >
class oliver
{
public:
    // ... niewazne teraz szczegoly
};

ale nie można później tego wykorzystać, to moim zdaniem w późniejszych wersjach (może nawet już) będzie to zaimplementowane (korzystam ze starej wersji z Code::Blocks 10.05).

Testy wykonane na środowisku Visual Studio 2010 wskazują, że kompilator w tym środowisku interpretuje dla szablonów parametry stałe znane w czasie kompilacji tylko jako stałe dosłowne (wpisane wprost w miejscu parametru) oczywiście przerzutowane na void*. Stąd taki fragment kodu w tym środowisku kompiluje się:

C/C++
#include <iostream>


using namespace std;

const int adres = 0x400000; // zasieg globalny


template < void * wsk >
class oliver
{
public:
    // ... niewazne teraz szczegoly
};


int main()
{
   
    //oliver <(void *)adres> var1;// error C2975: 'wsk' : invalid template argument for 'oliver', expected compile-time constant expression
    oliver < reinterpret_cast < void *>( 100 ) > var2;
   
   
    return 0;
}
Z kolei Embarcadero RAD Studio X2 C++ builder jest nieco bardziej pobłażliwy i jako parametr szablonu, który jest znany w czasie kompilacji bierze również zmienną (stałą) z przydomkiem const oczywiście również przerzutowaną na void*. Co więcej, szablon może przyjąć jako stałą zmienną, będącą wskaźnikiem typu void* czego visual 2010 i gcc nie "trawili".
Tak więc taki fragment kodu w tym środowisku kompiluje się prawidłowo:
C/C++
#include <iostream>

using namespace std;

const int adres = 0x400000; // zasieg globalny, musi byc const
void * wskaznik = reinterpret_cast < void *>( adres );


template < void * wsk >
class oliver
{
public:
   
};

int main()
{
   
    oliver <( void * ) adres > var1;
    oliver < reinterpret_cast < void *>( 100 ) > var2;
    oliver < wskaznik > var3;
    cout << "Udalo sie" << endl;
    return 0;
}

Przeanalizowałem też dokładnie tekst "Pasji c++" i wynika z niego, że autor pracował w środowisku Borland C++ 5.0 co wyjaśniałoby dlaczego jemu to działało. Widać Borland był bardziej "wyrozumiały" co do stałych znanych w czasie kompilacji.
Mogę powiedzieć, że moja ciekawość została zaspokojona :-)
 
P-66812
« 1 »
  Strona 1 z 1