Boshqa bir bo'shliq * mavzusi; Men shunchaki so'rashim kerak, chunki men shubhalanaman

Ok, muddling though Stack on the particulars about void*, books like The C Programming Language (K&R) and The C++ Programming Language (Stroustrup). What have I learned? That void* is a generic pointer with no type inferred. It requires a cast to any defined type and printing void* just yields the address.

Yana nimani bilaman? void * kodini o'zgartirib bo'lmaydi va shuning uchun juda ko'p narsalarni bilib olgan bo'lsam-da, juda kam tushunish mumkin bo'lgan C/C ++ dagi element.

* (char *) void * kabi, lekin generic işaretçisi uchun hech qanday ma'noga ega bo'lmagan narsa, bu qanday bo'lishi kerakligini bilish kerakligini tushunaman Qiymatni olish uchun menga kerak. Men Java programmuvchisan; Men umumiy turlarni tushunaman, lekin bu men bilan kurashadigan narsa.

Shunday qilib, ba'zi kodlarni yozdim

typedef struct node
{
  void* data;
  node* link;
}Node;

typedef struct list
{
   Node* head;
}List;

Node* add_new(void* data, Node* link);

void show(Node* head);

Node* add_new(void* data, Node* link)
{
  Node* newNode = new Node();
  newNode->data = data;
  newNode->link = link;

  return newNode;
}

void show(Node* head)
{
  while (head != nullptr)
  {
      std::cout << head->data;
      head = head->link;
  }
}

int main()
{
  List list;

  list.head = nullptr;

  list.head = add_new("My Name", list.head);

  list.head = add_new("Your Name", list.head);

  list.head = add_new("Our Name", list.head);

  show(list.head);

  fgetc(stdin);

  return 0;
}

Men keyinroq xotira ajratishni muhokama qilaman. void * da saqlangan turini bilmasam, qanday qilib qiymatni olishim mumkin? Ushbu , demoqchi bo'lishim kerak turini bilib oling va bu void * ga kirsangiz, bu erda

Nima uchun men hamkorlikni amalga oshirish uchun void * ni kutmoqdaman va kompilyator, uyma yoki birikma bo'yicha ba'zi bir qaydnomada o'zida yashirincha turini avtomatik ravishda chiqarib tashlaydi?

0
Menimcha void * dan foydalanish: Window CWnd sinfida void * data </​​code> bo'lishi mumkin. Bu ma'lumotlarning nima ekanligini bilmaydi va u g'amxo'rlik qilmaydi. Ushbu ma'lumotlar bilan hech narsa qilmaydi, faqatgina men uchun ushlab turadi. Ayni paytda mening kodim thingamabob ni ushbu ma'lumotlar ga saqlab qolishi mumkin. Mening kodim ma'lumotlar har doim thingamabob kodini saqlab qoladi deb o'ylaydi, bu mening kodim ushbu ma'lumotlar a'zolariga kiradigan yagona koddir. Mening kodim turi "biladi", lekin CWnd emas.
qo'shib qo'ydi muallif Mooing Duck, manba

5 javoblar

Keyinroq xotira ajratishni boshqaraman. Men bo'sh joy * da saqlanadigan turni tushunmasam, qanday qilib qiymatni olishim mumkin?

Siz qilolmaysiz. kerak , uni bekor qilishdan oldin, ko'rsatgichni ko'chirish mumkin bo'lgan joriy turlarni bilish.

Umumiy turdagi foydalanish uchun quyidagi ikkita variant mavjud:

  1. Agar C ++ 17 kompilyatoridan foydalansangiz, < kodi> std :: har qanday .
  2. Kattalashtirish kutubxonalaridan foydalansangiz, boost: har qanday .
5
qo'shib qo'ydi
qo'shib qo'ydi muallif R Sahu, manba
C ++ 17da @ shaxrida std :: any mavjud
qo'shib qo'ydi muallif Swift - Friday Pie, manba
C yoki c ++ da pure genericsni qo'llashning hech qanday usuli yo'qmi?
qo'shib qo'ydi muallif Mushy, manba

Java'dan farqli o'laroq, C/C ++ da xotira ko'rsatgichlari bilan ishlayapsiz. Hech qanday encapsulation yo'q. void * turi, o'zgaruvchining xotiradagi manzildir. Hech narsa u erda saqlanishi mumkin. int * kabi bir natija bilan siz derazaga nima deyilganligini aytasiz. Bundan tashqari, derleyici turi turini ( int uchun 4 baytni ayt) biladi va u holda bu manzilda 4 ga teng bo'ladi (granularlik/xotira moslashuvi). Yuqorida esa, kompilyatorga kompilyatsiya vaqtida mustahkamlik tekshiruvini amalga oshiradigan turni berasiz. Keyin emas. Bu void * bilan bo'lmadi.

Qisqasi, siz yalang'och metall ishlayapsiz. Bundaylar derleyici direktivalaridir va runtime ma'lumotlariga ega emas. Bundan tashqari, siz dinamik ravishda yaratilgan narsalarni kuzatib bo'lmaydi. Bu faqat narsa ni qaerda saqlashingiz mumkin bo'lgan ajratilgan xotira segmenti.

1
qo'shib qo'ydi

Qoidada saqlangan turdagi ma'lumotni tushunmayotgan bo'lsam, unda qiymatni qanday olish mumkin

Siz yo'q.

Siz nima qila olsangiz, void * da saqlangan turdagi yozuvni yozib olishingiz mumkin.

In , void* is used to pass around a binary chunk of data that points at something through one layer of abstraction, and recieve it at the other end, casting it back to the type that the code knows it will be passed.

void do_callback( void(*pfun)(void*), void* pdata ) {
  pfun(pdata);
}

void print_int( void* pint ) {
  printf( "%d", *(int*)pint );
}

int main() {
  int x = 7;
  do_callback( print_int, &x );
}

here, we forget thet ype of &x, pass it through do_callback.

Keyinchalik void * kodi do_callback yoki biladi int * . Shunday qilib, uni orqaga qaytaradi va uni int sifatida ishlatadi.

void * va iste'molchi void (*) (void *) birlashtirildi. Yuqoridagi kod "provayder to'g'ri", lekin tasdiqlash tizimda mavjud emas; Buning o'rniga, biz void * kodini int * deb biladigan kontekstda ishlatishimizdan kelib chiqadi.


C ++ da siz shunga o'xshash tarzda void * dan foydalanishingiz mumkin. Lekin siz ham farasingiz olishingiz mumkin.

Suppose you want a pointer to anything printable. Something is printable if it can be << to a std::ostream.

struct printable {
  void const* ptr = 0;
  void(*print_f)(std::ostream&, void const*) = 0;

  printable() {}
  printable(printable&&)=default;
  printable(printable const&)=default;
  printable& operator=(printable&&)=default;
  printable& operator=(printable const&)=default;

  template
  printable( T(&t)[N] ):
    ptr( t ),
    print_f( []( std::ostream& os, void const* pt) {
      T* ptr = (T*)pt;
      for (std::size_t i = 0; i < N; ++i)
        os << ptr[i];
    })
  {}
  template
  printable( char(&t)[N] ):
    ptr( t ),
    print_f( []( std::ostream& os, void const* pt) {
      os << (char const*)pt;
    })
  {}
  template, printable>{}, int> =0
  >
  printable( T&& t ):
    ptr( std::addressof(t) ),
    print_f( []( std::ostream& os, void const* pt) {
      os << *(std::remove_reference_t*)pt;
    })
  {}
  friend
  std::ostream& operator<<( std::ostream& os, printable self ) {
    self.print_f( os, self.ptr );
    return os;
  }
  explicit operator bool()const{ return print_f; }
};

Men qilgan narsam "C ++" da ("Java tipidagi yo'qotishlar" ga o'xshash) "tipdagi yo'qotish" deb nomlangan usul.

void send_to_log( printable p ) {
  std::cerr << p;
}

Live example.

Bu erda bosma kontseptsiyasiga maxsus "virtual" interfeys yaratilgan.

Turi hech qanday haqiqiy interfeysni qo'llab-quvvatlamasligi kerak (ikkilamchi tartib talablari yo'q), faqat ma'lum bir sintaksikni qo'llab-quvvatlashi kerak.

O'zboshimchalik turi uchun o'z virtual dispetcherlik tizimini yaratamiz.

This is used in the C++ standard library. In there is std::function, and in there is std::any.

std::any is void* that knows how to destroy and copy its contents, and if you know the type you can cast it back to the original type. You can also query it and ask it if it a specific type.

Yuqoridagi turdagi tozalash texnikasi yordamida std :: any ni aralashtirish siz o'zboshimchalik bilan o'rdak-terilgan interfeyslar bilan muntazam turdagi (qiymatlar, mos yozuvlar kabi) yaratishga imkon beradi.

0
qo'shib qo'ydi

Sizning chalkashlik odatiy Java dasturlari bilan shug'ullanish uchun paydo bo'ldi. Java kodi har bir ob'ektning nomi, turi, o'lchami va ma'lumotlarini saqlaydigan bir xil ma'lumotlar bazasiga berilgan RAMning funktsiyasi berilgan virtual mashinaga oid ko'rsatmalar to'plami. Siz o'qiyotgan tilni dasturlash tili CPU uchun ko'rsatma sifatida tuzilgan bo'lishi kerak. C va C ++ tillari tomonidan ishlatiladigan mavjud model, ba'zi platformalar va OS uchun tuzilgandan so'ng kodning samarali ishlashi uchun ko'plab ommabop operatsion tizimlarning yuqori qismiga qurilgan. Tabiiyki, bu tashkilot C ++ da mashhur RTTIdan boshqa turdagi tovush ma'lumotlarini o'z ichiga olmaydi.

Sizning ishingiz uchun RTTI to'g'ridan-to'g'ri foydalana olmaysiz, agar siz ma'lumotni saqlaydigan yalang'och ko'rsatgichingiz atrofida sarmalarni yaratmasangiz.

Aslida, C ++ kutubxonasida ISO standarti bilan aniqlangan bo'lsa, foydalanish mumkin va portativ bo'lgan konteyter sinf shablonlarining keng to'plami mavjud. 3/4 standarti odatda STL deb ataladigan kutubxonaning ta'rifidir. Ularni ishlatish yalang'och ko'rsatgichlar bilan ishlashdan afzalroq, agar biron bir sababga ko'ra o'z konteynerini yaratmoqchi bo'lsangiz. Ma'lum vazifani bajarish uchun faqat C ++ 17 standarti ilgari kutubxonada mavjud bo'lgan std :: any sinfini taqdim etdi. Tabiiyki, uni qayta ishlash yoki ba'zi hollarda std :: variant bilan almashtirish mumkin.

0
qo'shib qo'ydi

Void * dan foydalanishning asosiy sababi shundaki, turli xil narsalar ko'rsatilishi mumkin. Shunday qilib, int * yoki Node * yoki boshqa bir narsadan o'tishim mumkin. Lekin siz turini yoki uzunligini bilmasangiz, u bilan hech narsa qila olmaysiz.

Lekin agar siz uzunligini bilsangiz, turini bilmasdan ko'rsatgan xotirani ko'rib chiqishingiz mumkin. Uni char * sifatida ishlatish bitta bayt bo'lgani uchun ishlatiladi, shuning uchun bo'sh joy * va bir qator bayt bo'lsa, xotirani boshqa joyga nusxalash yoki noldan chiqarish mumkin.

Bundan tashqari, agar u sinf uchun ko'rsatgich bo'lsa, lekin siz ota-onangiz yoki meros qilib olingan sinf bo'lganligini bilmasangiz, unda qaysi birini aytib beradigan ma'lumotlarni o'z ichiga olgan bayroqni topib olishingiz mumkin. Lekin nima bo'lishidan qat'i nazar, siz boshqa funksiyaga o'tishdan ko'proq narsani talab qilmoqchi bo'lsangiz, uni biror narsa qilishingiz kerak. char * ishlatish uchun eng oddiy bir bayt qiymatidir.

0
qo'shib qo'ydi