web-gelistirme-sc.com

Void * ne anlama gelir ve nasıl kullanılır?

Bugün başkalarının kodlarını okurken, void *func(void* i); gibi bir şey gördüm, sırasıyla bu void*, işlev adı ve değişken türü için burada ne anlama geliyor?

Ayrıca, bu tür işaretçiyi ne zaman kullanmamız ve nasıl kullanmamız gerekir?

127
OneZero

void için bir işaretçi "genel" bir işaretçi türüdür. Bir void * açıkça bir döküm kullanmadan başka bir işaretçi türüne dönüştürülebilir. Bir void * kuralını ihlal edemezsiniz veya onunla işaretçi aritmetik yapamazsınız; önce işaretçiyi tam bir veri türüne dönüştürmelisiniz.

void *, aynı kodda farklı işaretçi tipleriyle çalışmanız gereken yerlerde kullanılır. Sıkça alıntı yapılan bir örnek, kütüphane işlevi qsort:

void qsort(void *base, size_t nmemb, size_t size, 
           int (*compar)(const void *, const void *));

base, bir dizinin adresi, nmemb, dizideki öğelerin sayısı, size, her öğenin boyutu ve compar, bir işlevin göstericisidir Bu, dizinin iki öğesini karşılaştırır. Buna şöyle denir:

int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);

iArr, dArr ve lArr dizi ifadeleri, işlev türündeki dizi türlerinden işaretçi türlerine örtük olarak dönüştürülür ve her biri örtük olarak "pointer" int/double/long "ila" işaretçiyi void "için.

Karşılaştırma fonksiyonları şöyle görünür:

int compareInt(const void *lhs, const void *rhs)
{
  const int *x = lhs;  // convert void * to int * by assignment
  const int *y = rhs;

  if (*x > *y) return 1;
  if (*x == *y) return 0;
  return -1;
}

void * kabul edilerek, qsort herhangi bir türdeki dizilerle çalışabilir.

void * kullanmanın dezavantajı, pencereden ve yaklaşmakta olan trafiğe güvenlik türünü atmanızdır. Yanlış karşılaştırma rutini kullanmaktan seni koruyacak hiçbir şey yok:

qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);

compareInt, argümanlarının ints ile işaret etmesini bekliyor, ancak aslında doubles ile çalışıyor. Derleme zamanında bu sorunu yakalamanın yolu yoktur; sadece cevapsız bir dizi ile kaplayacaksınız.

161
John Bode

Bir boşluk kullanmak *, işlevin belirli bir tür olması gerekmeyen bir işaretçiyi alabileceği anlamına gelir. Örneğin, soket işlevlerinde,

send(void * pData, int nLength)

bu, örneğin birçok yolla arayabileceğiniz anlamına gelir.

char * data = "blah";
send(data, strlen(data));

POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));
22
TheSteve

C bu konuda dikkat çekicidir. Biri boşluğun hiçbir şey olmadığını söyleyebilir, boşluk * her şeydir (her şey olabilir)

Sadece bu küçük * fark yaratır.

Rene işaret etti. Bir boşluk *, bazı konumlara yönelik bir İşaretçidir. Nasıl yorumlanacağı, kullanıcıya bırakılmıştır.

C de opak tiplere sahip olmanın tek yolu budur. Çok belirgin örnekler örneğin glib veya genel veri yapısı kütüphanelerinde bulunabilir. "C Arayüzleri ve uygulamaları" bölümünde çok ayrıntılı olarak ele alınmıştır.

Tüm bölümü okumanızı ve "onu almak için" bir işaretçi kavramını anlamaya çalışmanızı öneririm.

7
Friedrich
void*

bir 'varsayım yok belleğe hangi türün orada depolandığını göstericidir'. Örneğin, işlevine bir argüman iletmek istiyorsanız ve bu argüman birkaç tür olabilir ve işlevde her bir tür işleyecektir.

3
René Kolařík

İşaretçilerle ilgili bu makaleye bir göz atabilirsiniz http://www.cplusplus.com/doc/tutorial/pointers/ ve şu bölümü okuyun: geçersiz işaretçiler .

Bu, C dili için de geçerlidir.

Boş işaretçi türü, özel bir işaretçi türüdür. C++ 'da boşluk, türün yokluğunu temsil eder; bu nedenle, boşluk işaretçiler, türü olmayan bir değere işaret eden işaretçilerdir (ve dolayısıyla belirsiz bir uzunluk ve belirlenmemiş dereference özellikleri).

Bu, boşluk işaretçilerinin bir tamsayı değerinden veya bir kayan noktadan bir karakter dizisine kadar herhangi bir veri türünü işaret etmesini sağlar. Ancak, bunun karşılığında büyük bir kısıtlamaya sahipler: Onlarla gösterilen veriler doğrudan reddedilemez (bu mantıklı, çünkü bizim için geçerli bir türümüz yok) ve bu nedenle adresi her zaman geçersiz göstergeye yönlendirmek zorunda kalacağız Tespit edilmeden önce somut bir veri türüne işaret eden başka bir işaretçi türü.

3
A.G.

Bir boş işaretçi, genel işaretçi olarak bilinir. Örnek bir pthread senaryosuyla açıklamak istiyorum.

Thread işlevi prototip olarak

void *(*start_routine)(void*)

Pthread API tasarımcıları, thread işlevinin argümanı ve dönüş değerlerini değerlendirdi. Bu şeyler genel yapılırsa, argüman olarak gönderirken void * için cast yazın. Benzer şekilde dönüş değeri void * 'den alınabilir (Fakat hiçbir zaman thread işlevinden dönüş değerleri kullanmadım).

void *PrintHello(void *threadid)
{
   long tid;

   // ***Arg sent in main is retrieved   ***
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      //*** t will be type cast to void* and send as argument.
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);   
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }    
   /* Last thing that main() should do */
   pthread_exit(NULL);
}
3
Jeyaram

a void* bir işaretçidir, ancak gösterdiği şeyin türü belirtilmez. Boşluk işaretçisini bir işleve geçirdiğinizde, daha sonra onu kullanmak için işlevin doğru türüne geri döndürmek için türünün ne olduğunu bilmeniz gerekir. Örneğinizde, thread işlevi olarak kullanılan tam olarak prototip içeren işlevleri kullanan pthreads öğesinde örnekler göreceksiniz. Daha sonra void* argümanını seçtiğiniz bir genel veri türüne işaretçi olarak kullanabilir ve ardından iş parçacığı işlevinizde kullanmak için o türe geri döndürebilirsiniz. Boşluk işaretçilerini kullanırken dikkatli olmanız gerekir, ancak gerçek tipte bir göstericiye dönmezseniz, her türlü soruna yol açabilirsiniz.

1

C11 standardı (n1570) §6.2.2.3 al1 p55:

void için bir işaretçi, bir işaretçiden herhangi bir nesne türüne dönüştürülebilir. Herhangi bir nesne türüne yönelik bir işaretçi, geçersiz kılmak ve tekrar geri dönmek için bir işaretleyiciye dönüştürülebilir; sonuç, orijinal göstergeyle eşit olarak karşılaştırılmalıdır.

Herhangi bir nesne türüne bir işaretçi depolamak için bu jenerik işaretleyiciyi kullanabilirsiniz, ancak onunla her zamanki aritmetik işlemleri kullanamazsınız ve saptamazsınız.

1
md5

İşlev isteğe bağlı bir türe bir gösterici alır ve böyle bir döner.

0
glglgl