Bugün başkalarının kodunu okurken şöyle bir şey gördüm void *func(void* i);
, void*
burada sırasıyla işlev adı ve değişken türü için bu ne anlama geliyor?
Ek olarak, bu tür bir işaretçiyi ne zaman ve nasıl kullanmalıyız?
Bugün başkalarının kodunu okurken şöyle bir şey gördüm void *func(void* i);
, void*
burada sırasıyla işlev adı ve değişken türü için bu ne anlama geliyor?
Ek olarak, bu tür bir işaretçiyi ne zaman ve nasıl kullanmalıyız?
malloc
ve calloc
. Man sayfası şöyle devam eder: "... herhangi bir yerleşik veri türü için uygun şekilde hizalanmış olan ayrılmış belleğe bir işaretçi döndür."
Yanıtlar:
İşaretçi void
, "genel" bir işaretçi türüdür. A void *
, açık bir atama olmadan başka herhangi bir işaretçi tipine dönüştürülebilir. Onunla bir void *
işaretçi aritmetiği yapamazsınız veya bir işaretçi aritmetiği yapamazsınız; önce onu tam bir veri türüne bir işaretçiye dönüştürmelisiniz.
void *
genellikle aynı kodda farklı işaretçi türleriyle çalışabilmeniz gereken yerlerde kullanılır. Yaygın olarak alıntı yapılan bir örnek, kütüphane işlevidir qsort
:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
base
bir dizinin adresidir, dizideki nmemb
öğelerin sayısıdır, size
her öğenin boyutudur compar
ve dizinin iki öğesini karşılaştıran bir işleve göstericidir. Şöyle çağrılır:
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);
Dizi ifadeleri iArr
, dArr
ve lArr
işlev çağrısında örtülü olarak dizi türlerinden işaretçi türlerine dönüştürülür ve her biri örtük olarak "göstericiden int
/ double
/ long
" ye "işaretçi void
" ye dönüştürülür.
Karşılaştırma işlevleri şuna benzer:
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;
}
Kabul ederek void *
, qsort
her türden diziyle çalışabilir.
Kullanmanın dezavantajı, void *
yazım güvenliğini pencereden dışarı ve yaklaşan trafiğe atmanızdır. Sizi yanlış karşılaştırma rutinini kullanmaktan koruyacak hiçbir şey yok:
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);
compareInt
argümanlarının int
s'yi göstermesini bekliyor , ancak aslında double
s ile çalışıyor . Derleme sırasında bu sorunu yakalamanın bir yolu yoktur; sadece yanlış sıralı bir dizi ile sonuçlanacaksınız.
void*
a'nın bir işlev işaretçisine dönüştürülebileceği garanti edilmez . Ancak veri işaretçileri için söylediğiniz şey geçerli.
Bir void * kullanmak, işlevin belirli bir tür olması gerekmeyen bir işaretçi alabileceği anlamına gelir. Örneğin, soket işlevlerinde,
send(void * pData, int nLength)
bu, pek çok şekilde arayabileceğiniz anlamına gelir
char * data = "blah";
send(data, strlen(data));
POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));
C bu açıdan dikkate değerdir. Söyleyebileceğim tek void
hiçlik olduğu void*
(her şey olabilir) her şeydir.
*
Farkı yaratan sadece bu kadar küçük .
Rene işaret etti. A void *
, bir konum için bir İşaretçidir. Nasıl "yorumlanacağı" kullanıcıya bırakılmıştır.
C'de opak türlere sahip olmanın tek yolu budur. Çok belirgin örnekler, örneğin glib veya genel veri yapısı kitaplıklarında bulunabilir. "C Arayüzleri ve uygulamalarında" çok ayrıntılı olarak ele alınmıştır.
Tam bölümü okumanızı ve "elde etmek" için bir işaretçi kavramını anlamaya çalışmanızı öneririm.
void*
'hangi tipin depolandığı varsayımları olmaksızın belleğe bir göstericidir'. Örneğin, işlevine bir bağımsız değişken iletmek istiyorsanız ve bu bağımsız değişken birkaç türde olabilir ve işlevde her türü ele alırsınız.
İşaretçilerle ilgili bu makaleye göz atabilir http://www.cplusplus.com/doc/tutorial/pointers/ ve şu bölümü okuyabilirsiniz: boşluk işaretçileri .
Bu aynı zamanda C dili için de geçerlidir.
Boş işaretçi türü özel bir işaretçi türüdür. C ++ 'da void, türün yokluğunu temsil eder, bu nedenle void işaretçileri, türü olmayan bir değere işaret eden işaretçilerdir (ve dolayısıyla ayrıca belirsiz bir uzunluk ve belirlenmemiş özümleme özellikleri).
Bu, void işaretçilerinin bir tamsayı değerinden veya kayan değerden karakter dizisine kadar herhangi bir veri türünü işaret etmesine izin verir. Ancak karşılığında büyük bir sınırlamaları vardır: onlar tarafından gösterilen veriler doğrudan referans alınamaz (bu mantıklıdır, çünkü başvurulacak türümüz yoktur) ve bu nedenle adresi her zaman boş göstericiye çevirmek zorunda kalacağız. referansını kaldırmadan önce somut bir veri türüne işaret eden başka bir işaretçi türü.
Boş gösterici, genel işaretçi olarak bilinir. Örnek bir pthread senaryosu ile açıklamak istiyorum.
Thread fonksiyonu prototipe sahip olacaktır:
void *(*start_routine)(void*)
Pthread API tasarımcıları, evre işlevinin bağımsız değişkenini ve dönüş değerlerini değerlendirdi. Bu şeyler jenerik yapılırsa, argüman olarak gönderirken void * 'e cast yazabiliriz. benzer şekilde dönüş değeri void * 'dan alınabilir (Ama ben hiçbir zaman thread fonksiyonundan 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);
}
pthread_exit(NULL);
yerine return 0;
arayasınız?
a void*
bir göstericidir, ancak işaret ettiği şeyin türü belirtilmemiştir. Bir işleve bir geçersiz gösterici ilettiğinizde, onu kullanmak için daha sonra işlevde bu doğru türe geri döndürmek için türünün ne olduğunu bilmeniz gerekir. pthreads
Örneğinizde iş parçacığı işlevi olarak kullanılan prototipi tam olarak kullanan işlevleri kullanan örnekler göreceksiniz . Daha sonra void*
bağımsız değişkeni, seçtiğiniz genel bir veri türüne işaretçi olarak kullanabilir ve ardından iş parçacığı işlevinizde kullanmak için bu türe geri dönüştürebilirsiniz. Void işaretçileri kullanırken dikkatli olmalısınız, ancak gerçek türündeki bir işaretçiye geri dönmediğiniz sürece her türlü problemle karşılaşabilirsiniz.
C11 standardı (n1570) §6.2.2.3 al1 p55 diyor ki:
İşaretçi
void
, bir işaretçiye veya işaretçiden herhangi bir nesne türüne dönüştürülebilir. Herhangi bir nesne türüne bir işaretçi, bir işaretçiye void'e ve tekrar geri dönüştürülebilir; sonuç orijinal göstericiye eşit olmalıdır.
Herhangi bir nesne türüne bir işaretçi depolamak için bu genel işaretçiyi kullanabilirsiniz, ancak bununla olağan aritmetik işlemleri kullanamazsınız ve onu dikkate alamazsınız.
bu, işaretçi http://www.cprogramming.com/tutorial/c/lesson6.html hakkında daha fazla bilgi almak için bu bağlantıyı kullanabileceğiniz anlamına gelir