8

Ciçinde aşırı işlevi uygulamak çalışılıyor ve ben çok yakınım. C99 kullanıyorum, bu yüzden C11'de tanıtılan _Generic anahtar kelimesi bana ulaşılamıyor. Bazı çalışma kodlarını geliştirdim, ama derlediğimde birkaç uyarı alıyorum.Fonksiyon - derleyici uyarıları

Çalışma örneği:

#include <stdio.h> 

#define print(x)                  \ 
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int(x) , \ 
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string(x), \ 
(void)0)) 


void print_int(int i) { 
    printf("int: %d\n", i); 
} 

void print_string(char* s) { 
    printf("char*: %s\n", s); 
} 

int main(int argc, char* argv[]) { 

    print(1); 
    print("this"); 

    return 0; 
} 

Derleme aşağıdaki uyarıları oluşturur: burada, biraz daha ayıklama bilgi için

gcc overload.c -o main 
overload.c: In function 'main': 
overload.c:19: warning: passing argument 1 of 'print_string' makes pointer from integer without a cast 
overload.c:20: warning: passing argument 1 of 'print_int' makes integer from pointer without a cast 

ana işlevi önişlemci çalışmalarını yapar sonra neye benzediği:

int main(int argc, char* argv[]) { 

__builtin_choose_expr(__builtin_types_compatible_p(typeof(1), int), print_int(1) , __builtin_choose_expr(__builtin_types_compatible_p(typeof(1), char[]), print_string(1), (void)0)); 
__builtin_choose_expr(__builtin_types_compatible_p(typeof("this"), int), print_int("this") , __builtin_choose_expr(__builtin_types_compatible_p(typeof("this"), char[]), print_string("this"), (void)0)); 

return 0; 
} 

Derleme uyarılarını nasıl giderebilirim? Çalışma kodunuz var mı?

+0

Yazılıma "print_string (1)" ve "print_int" ("this") 'e yönelik çağrıların uyarılara neden olduğuna inanıyorum, ancak türler eşleşmediği için bu çağrılar hiçbir zaman olmamalıdır. – tjwrona1992

+0

'print_int (x)' veya 'print_string (x)' yi seçmek yerine, print_int' veya 'print_string' öğesini seçerseniz ve seçilen işlevi (pointer) x'e uygularsanız ne olur? – user2357112

+0

@ user2357112, Bunu yapmayı nasıl yaparım? Fonksiyon işaretçileriyle pek iyi değilim. – tjwrona1992

cevap

7

, bu çalışması gerekir:

#define print(x)                  \ 
(__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int , \ 
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \ 
(void)0))(x)) 

Bu print_int veya print_string seçeneğini seçer ve ardından x tercih fonksiyonu uygular.

+1

gcc 4.9 ve clang 3.5 üzerinde çalışma doğrulandı. – Leandros

+0

Bu iyi, belirtilen tür desteklenmediğinde bir derleyici hatası tetikleyecektir. –

+0

Evet bu işe yarıyor. Teşekkür ederim! – tjwrona1992

0

uyarı #define bölümünde bazı türü çevrim yaparak bastırılmış, ama muhtemelen en iyi ya da hiç bile iyi bir çözüm değildir böyle hissediyorum ...

değiştirme fonksiyonu #define çağırır edilebilir buna bölümü:

print_string((char*)x) 
print_int((int)x) 

gerçekten bu sadece yanlış geliyor çünkü birisi olsa daha iyi bir çözümle geliyor umut ... teoride

+0

Ben sadece aynı fikir geldi, ancak, sadece size farklı bir uyarı verecektir: -Wpointer-int-cast'. – Leandros

+0

"gcc -Wall" ile derledim ve uyarılardan kurtuluyor. Ancak g ++ ile derlemek, sayısız hatayla tamamen başarısız olacaktır. – tjwrona1992

+2

C++ 'da başarısız olur, çünkü gC'nin belgelerine göre, yerleşiklerin hiçbiri C++'da kullanılamaz. – Leandros

2

Yapılarda bulunan GNU page, seçilmeyen dalların hala sözdizimi hataları oluşturabileceğini, ancak eşleşmeyen türlerin söz dizimi hataları olduğunu göremediğimi söylüyor. Eğer tip bağımlı seçim dışarı işleve argümanlar taşıdığınızda

Neyse, uyarı kurtulabilirsiniz. Yani bir yorumda önerilen user2357112 ne Yani

choose_type_of(x, int, print_int, 
choose_type_of(x, char[], print_string, pass))(x) 

yapmak yerine

choose_type_of(x, int, print_int(x), 
choose_type_of(x, char[], print_string(x), (void) 0)) 

arasında, (sırayla pseudocode daha okunabilir hale getirmek için). Benzer bir çözüm üzerinde çalışıyordum, ama çalışmak için varsayılan kısmı (pass yukarıda) almak için zor bir zaman geçirdim. (void)(x)'a genişletmek için (void) kullandığımda, benzersiz bir parantez hakkında bir hata alıyorum.

aşağıda çözüm argumanlarini kullanmayan bir varsayılan yazdırma işlevi oluşturur. Muhtemelen mevcut olmayan bir işlev olabilir, bu yüzden bağlantı yaparken veya bir hata üreten başka bir şeyde sorunlar vardır.

#include <stdio.h> 

#define print(x)             \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), \ 
     int), print_int,           \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), \ 
     const char[]), print_string,        \ 
    print_any))(x) 


void print_int(int i) { 
    printf("int: %d\n", i); 
} 

void print_string(const char *s) { 
    printf("char[]: %s\n", s); 
} 

void print_any() { 
    printf("unknown\n"); 
} 

int main(void) 
{ 
    int n = 9; 
    const char str[] = "hello"; 

    print(n); 
    print(str); 

    print(1); 
    print("this"); 

    print(3.2); 

    return 0; 
} 
+0

'(void)' işe yaramadı çünkü bir ifade seçiyoruz, bir dizi belirteç değil ve '(void)' tam bir ifade değil. – user2357112

+0

@ user2357112: İyi nokta. Varsayılan maddede bir derleyici hatası oluşturmak, muhtemelen daha iyi bir yaklaşımdır. –

1

İşte işlevlerin farklı gerçekleştiren birkaç yöntemlerle bir örnek verilmiştir.

Bir afiş inşa açma işlemlerinde bu

GNU sayfasını dalları hala sözdizimi hataları verebilir seçmedi söylüyor sözü ama sözdizimi hataları nasıl uyumsuz türleri görmek için başarısız. onlar bahsettiğiniz sözdizimi hataları İnanıyorum

yüzünden dedikleri asla rağmen bazı işlevlere parametre tipleri, yanlış olduğunu görebilirsiniz derleyici ön işlenmesi sonra olsun derleyici uyarıları bulunmaktadır. Çözüm (ki bence oldukça düzgün), derleyiciden türlerini gizlemenin bir yolunu bulmak. Bariz yol varargs, OP'in sorusunun şu anki cevabı ise daha az açık olan yoldur.

https://github.com/harryjackson/doc/blob/master/c/overload_c_functions.c

anahtarı yöntemi ile ...

#include <stdarg.h> 
#include <stdlib.h> 
#include <stdio.h> 

#define print(x)                  \ 
    (__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int , \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \ 
    (void)0))(x)) 

#define print1(x)                   \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int1(1,x) , \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string1(1,x), \ 
(void)0)) 

#define print2(x)                 \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), printer(1,x), \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), printer(2,x), \ 
(void)0)) 

#define TYPE_ID(x) __builtin_types_compatible_p(typeof(x), int ) * 1 \ 
       + __builtin_types_compatible_p(typeof(x), char[]) * 2 

#define print3(x) printer(TYPE_ID(x), x) 

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1] 

#define print4(x) \ 
    STATIC_ASSERT(TYPE_ID(x), __LINE__); \ 
    printer(TYPE_ID(x), x) 

void printer(int i, ...) { 
    va_list v; 
    va_start(v, i); 
    switch(i) { 
    case 1:{ 
      int arg = va_arg(v, int); 
      printf("int: %d\n", arg); 
      va_end(v); 
      break; 
      } 
    case 2:{ 
      char * arg = va_arg(v, char*); 
      printf("char*: %s\n", arg); 
      va_end(v); 
      break; 
      } 
    default: { 
       fprintf(stderr, "Unknown type, abort\n"); 
       abort(); 
      } 
    } 
} 

void print_int(int i) { 
    printf("int: %d\n", i); 
} 

void print_string(char* s) { 
    printf("char*: %s\n", s); 
} 
void print_int1(int i, ...) { 
    va_list v; 
    va_start(v, i); 
    int arg = va_arg(v, int); 
    printf("int: %d\n", arg); 
    va_end(v); 
} 

void print_string1(int i, ...) { 
    va_list v; 
    va_start(v, i); 
    char * arg = va_arg(v, char*); 
    printf("char*: %s\n", arg); 
    va_end(v); 
} 
int main(int argc, char* argv[]) { 
    int var = 1729; 
    double var1 = 1729; 
    //Type safe 
    //print(var1);//Comple time error 
    print(var); 
    print("print"); 

    /* Following are not Type Safe */ 
    print1(var1);// BAD... Does nothing. 
    print1(var); 
    print1("print1"); 

    print2(var1);// BAD... Does nothing. 
    print2(var); 
    print2("print2"); 

    //print3(var1);//Evil... Runtime error 
    print3(var); 
    print3("print3"); 

    //Type Safe 
    //print4(var1);//Comple time error 
    print4(var); 
    print4("print4"); 
    return 0; 
} 

Kaynak github üzerinde ...

Uyarılar yani tüm çözümler tip güvenli değil geçerlidir ve bu GNU tamamen özeldir birden argümanlar ... burada bulabilirsiniz

http://locklessinc.com/articles/overloading/

Tümü