2013-01-03 21 views
11

Bazı öğreticiler ve işlev işaretleyicileri ile ilgili bilgileri okurken, ISO C'deki bir işlev işaretçisine bir boşluk işaretçisinin apaçık bir şekilde atanmasının tanımlanmadığını öğrendim, derleme sırasında aldığım uyarıyı çözmenin herhangi bir yolu var mı? (örneğin, kodlamanın daha iyi bir yolu) ya da bunu görmezden gelmem gerekir mi?ISO C Void * ve Fonksiyon İşaretleyicileri

Uyarı:

ISO C forbids assignment between function pointer and 'void *' [-pedantic] 

Örnek Kodu:

void *(*funcPtr)(); 
funcPtr = GetPointer(); 

GetPointer bir boş işaretçisi, örneğin döner bir fonksiyondur

void *GetPointer(); 
+3

nasıl bir işleve bir boşluk işaretçi atama hakkında değil Işaretçi? –

+4

Teoride tanımlanmamıştır çünkü bazı makineler kod adresleri ve veri adresleri için farklı boyutlara sahipti. Pratikte, bugün en yaygın mimaride, kod ve veri adresleri aynı adres alanında aynı boyuttadır. –

+0

GetPointer() ne döndürüyor? Hatayı aldığınız ikinci satır mı? –

cevap

6

sayılı derleyici doğru olduğunu ve çok: C89 ve C99, sen (ki void *) veri işaretçileri arasında dönüştürmek edemez ve fonksiyon işaretçileri, bu nedenle uyarı çözmek için tek yol dönüyor Fonksiyondan bir fonksiyon gösterici.

(pratikte bu uyarıya rağmen çalışıyor ve hatta orada standart kütüphanede bu tutarsızlık olduğunu, ancak, Not - dlsym() fonksiyon işlev işaretçileri elde etmek için kullanılır, ancak void * döndürür - yani aslında sen uyarıyı gözardı edebilirsiniz Bu, kesinlikle konuşma davranışı tanımsız olmasına rağmen çalışacaktır.)

+0

Aslında kod çalışması, daha iyi olası kodlama stilleri hakkında bilgi edinmekle ilgilendiğim için (Bu yüzden bu kadar katı uyarıları neden kodluyorum), nedenleri, etkileri ve bunlardan sakınmanın yollarını anlama konusunda uyarılar ve daha fazla bilgi sahibi olmaktan daha az şey var. –

+0

@Tomwaivory Evet, görüyorum ve bu kesinlikle iyi bir uygulama. Bu durumda, dil ile yanlış olan bir şey :) Bu yüzden endişelenmeyin, uygulama bir teori ile aynı değildir, bir DS9k üzerinde çalışmadığınız sürece, bu UB ile çalışmaya devam eder, ve sen de yenebilirsin. C standartlarının üyeleri bir çubukla komşudur: D –

+0

Teşekkürler, iyi bildiğim, dili düzeltmek için elimden gelenin en iyisini yaparım :) –

2

Bu sorunu glib kullanarak karşılaştım. GSList gibi Glib veri yapıları genellikle void * verileri olarak adlandırılan bir alana sahiptir. Bir listenizdeki mağaza fonksiyonları istediğini ve buna benzer hataların bir grup var:

warning: ISO C forbids passing argument 2 of ‘g_slist_append’ between function pointer and ‘void *’ [-pedantic] 

Bu örnek kullanarak uyarıların bir demet oluşturur gcc -Wall -ansi -pedantic

typedef int (* func) (int); 

int mult2(int x) 
{ 
    return x + x; 
} 

int main(int argc, char *argv[]) 
{ 
    GSList *functions = NULL; 
    func f; 

    functions = g_slist_append(functions, mult2); 
    f = (func *) functions->data; 
    printf("%d\n", f(10)); 
    return 0; 
} 

yüzden sarılmış bir yapı içinde fonksiyon ve bütün uyarılar go away:

struct funcstruct { 
    int (* func) (int); 
}; 

int mult2(int x) 
{ 
    return x + x; 
} 

int main(int argc, char *argv[]) 
{ 
    GSList *functions = NULL; 
    struct funcstruct p; 
    p.func = mult2; 

    functions = g_slist_append(functions, &p); 
    p = * (struct funcstruct *) functions->data; 
    printf("%d\n", p.func(10)); 
    return 0; 
} 

Bu ekstra kod biraz birkaç uyarı yok etmek için olduğunu tartışılabilir, ama uyarılar üretmek için kodumu sevmiyorum. Ayrıca, yukarıdaki oyuncak örnekleridir. Yazmakta olduğum gerçek kodda, bir yapıdaki işlevlerin listesini sarmalamak oldukça yararlıdır.

Sorunlu olup olmadığını veya bunu yapmanın daha iyi bir yolu olup olmadığını öğrenmek isterim.

#include <dlfcn.h> 

int 
main(int argc, char *argv[]) 
{ 
    ... 
    void (*funcp)(void);  /* Pointer to function with no arguments */ 
    ... 
    *(void **) (&funcp) = dlsym(libHandle, argv[2]); 
} 
+0

Bu şekilde yaparsanız, listeyi 'p' kapsamı dışında kullanamazsınız, çünkü 'p' işaretçisi yalnızca 'p' kapsamında geçerlidir. Yani senin listen işe yaramaz olurdu. Ve yapı tipini yapmak tamamen gereksizdi. Eğer basitçe “p” yi int (* p) (int) olarak ilan etmiş olsaydınız, şu an sahip olduğunuzla hemen hemen aynı şekilde çalışır. – newacct

5

#include <dlfcn.h> 

/* Pointer to function with no arguments */ 
typedef void (functor_t*)(void); 

void load_symbol(functor_t* functor, void* dl_handle, const char* symbol_name) { 
    *(void**)functor = dlsym(dl_handle, symbol_name); 
} 

int 
main(int argc, char *argv[]) 
{ 
    // [...] 
    functor_t funcp; 
    // [...] 
    load_symbol(&funcp, libHandle, argv[2]); 
} 
+0

Birisi, daha ayrıntılı olarak nasıl çalıştığını açıklayabilir mi? –

+1

@MatthieuPoullet: Sağ tarafta, bir boşluk işaretçimiz var (void * '). Sol tarafta, bir fonksiyon işaretçisinin adresini alırız. '(Void **)' yi bir süreliğine görmezden gelerek, bir fonksiyon imlecine işaretçi en soldaki '*' işaretini kaldırır. '' '(Void **)' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'bir imleç imlecini işaret eden bir imlecin işaretçisine gösterilmesi gerektiğini söyler. Böylece, ödevin hem sol hem de sağ tarafları 'void * 'tipine sahiptir ve derleyici mutludur. – mtk

0

@WeinanLi cevap dayanarak, ama netlik için bir yardımcı işlevini kullanarak: Çok ilginç bu hileyi buldum tlpi-book yılında