Typedef fonksiyon işaretçisi?


460

Dinamik olarak DLL yüklemek nasıl öğreniyorum ama anlamıyorum bu hat

typedef void (*FunctionFunc)();

Bir kaç sorum var. Birisi onlara cevap verebilirse minnettar olurum.

  1. Neden typedefkullanılır?
  2. Sözdizimi tuhaf görünüyor; sonra voidbir işlev adı falan olmamalıdır? Anonim bir işleve benziyor.
  3. Bir işlevin bellek adresini saklamak için bir işlev işaretçisi oluşturulmuş mu?

Şu anda kafam karıştı; benim için bir şeyleri açıklayabilir misin?


5
Bağlantıya bir göz atın (son bölüm) learncpp.com/cpp-tutorial/78-function-pointers
enthusiasticgeek

9
Unutulmamalıdır ki c ++ 11 using FunctionFunc = void (*)();yerine kullanılabilir. Sadece bir tip için bir isim beyan ettiğiniz biraz daha açıktır (işaretçi işlev
görecek

sadece @ user362515'e eklemek için, bana biraz daha açık bir form:using FunctionFunc = void(void);
topspin

@topspin IIRC bu ikisi aynı değil. Biri bir işlev işaretçisi, diğeri işlev türüdür. Örtük dönüşüm var, bu yüzden işe yarıyor, IANA (C ++) L, böylece içeri girip beni düzeltebilirsiniz. Her durumda, niyet bir işaretçi türü tanımlamak ise ben ile sözdiziminin *biraz daha açık olduğunu düşünüyorum .
user362515

Yanıtlar:


463

typedefbir adı bir türle ilişkilendiren bir dil yapısıdır.
Bunu, orijinal türü kullandığınız gibi kullanırsınız, örneğin

  typedef int myinteger;
  typedef char *mystring;
  typedef void (*myfunc)();

onları gibi kullanmak

  myinteger i;   // is equivalent to    int i;
  mystring s;    // is the same as      char *s;
  myfunc f;      // compile equally as  void (*f)();

Gördüğünüz gibi, typedefed adını yukarıdaki tanımıyla değiştirebilirsiniz .

Zorluk, C ve C ++ 'da sözdizimi ve okunabilirlik işlevlerinin işaretçisinde yatmaktadır ve bu typedeftür bildirimlerin okunabilirliğini artırabilir. Bununla birlikte, sözdizimi uygundur, çünkü işlevler - diğer daha basit türlerden farklı olarak - bir dönüş değeri ve parametrelerine sahip olabilir, bu nedenle işlev için bir işaretçinin bazen uzun ve karmaşık bildirimi olabilir.

Okunabilirlik, işlev dizilerine ve diğer bazı dolaylı lezzetlere işaretçilerle gerçekten zor olmaya başlayabilir.

Üç sorunuzu cevaplamak için

  • Typedef neden kullanılır? Kodun okunmasını kolaylaştırmak için - özellikle işlevlere veya yapı adlarına işaretçiler için.

  • Sözdizimi garip görünüyor (işlev bildirimi için işaretçide) Bu sözdiziminin en azından başlangıçta okunması açık değildir. typedefBunun yerine bir bildirimin kullanılması okumayı kolaylaştırır

  • Bir işlevin bellek adresini saklamak için bir işlev işaretçisi oluşturulmuş mu? Evet, bir işlev işaretçisi bir işlevin adresini saklar. Bunun typedefsadece bir programın yazılmasını / okunmasını kolaylaştıran yapı ile bir ilgisi yoktur ; derleyici, gerçek kodu derlemeden önce typedef tanımını genişletir.

Misal:

typedef int (*t_somefunc)(int,int);

int product(int u, int v) {
  return u*v;
}

t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456

6
son örnekte, sadece 'kare' aynı şeyi ifade etmez, yani & square yerine fonksiyonun göstergesidir.
pranavk

2
Soru, ilk typedef örneğinizde formunuz var, typedef type aliasancak işlev işaretçileriyle sadece 2 argüman var gibi görünüyor typedef type. Diğer ad varsayılan olarak tür bağımsız değişkeninde belirtilen ada mı ayarlanmış?
dchhetri

2
@pranavk: Evet squareve &square(ve aslında *squareve **square) hepsi aynı işlev işaretçisine başvuruyor.
Jonathan Leffler

6
@ user814628: Ne istediğini pek belli değil. İle typedef int newname, sen yapıyoruz newnameiçin bir takma ad içine int. İle typedef int (*func)(int), funcbir takma ad oluşturuyorsunuz int (*)(int)- bir intargüman alarak ve bir intdeğer döndüren bir işaretçi işlevi .
Jonathan Leffler

10
Sanırım sipariş hakkında kafam karıştı. Typedef ile int (*func)(int), func'un bir takma ad olduğunu anlıyorum, sadece biraz karışık çünkü takma ad türle karışık. typedef int INTÖrnek olarak gitmek, typedef işlev işaretçisi formda olsaydı daha kolay olurdu typedef int(*function)(int) FUNC_1. Bu şekilde, tür ve takma adı bir ağ içine yerleştirilmek yerine iki ayrı tokende görebilirim.
dchhetri

188
  1. typedefdiğer ad türlerinde kullanılır; bu durumda aliasing ediyoruz FunctionFuncetmek void(*)().

  2. Aslında sözdizimi tuhaf görünüyor, şuna bir bakın:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
    
  3. Hayır, bu derleyiciye FunctionFunctürün bir işlev işaretçisi olacağını söyler, birini tanımlamaz , şöyle:

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"
    

27
typedefyok değil yeni bir tür beyan ederim. typedefaynı türde birçok tanımlı isme sahip olabilirsiniz ve bunlar farklı değildir (örn. işlevlerin aşırı yüklenmesi). adı nasıl kullanabileceğinize ilişkin typedefolarak, tanımlanmış bir adın tanımlandığı adla tam olarak eşdeğer olmadığı, ancak typedefaynı için birden çok tanımlanmış adların eşdeğer olduğu bazı durumlar vardır.
Şerefe ve s. - Alf

Ah şimdi anladım. Teşekkürler.
Jack Harvin

4
2. soruya verilen cevap için +1 - çok açık. Cevapların geri kalanı da açıktı, ama bu benim için öne çıkıyor :-)
Michael van der Westhuizen

33

typedefKelime olmadan, C ++ 'da bildirim, bir FunctionFuncargüman türünün işlevini döndürmek için bir tür işaretçi değişkeni bildirir void.

İle typedefyerine tanımlayan FunctionFunctürü için bir isim olarak.


5
Bunu düşünmek için gerçekten iyi bir yol. Diğer cevapları dikkatlice okursanız, OP'nin takma ad ve adın karışması hakkındaki karışıklığına gerçekten değinmezler. Bu yazıyı okuyarak yeni bir şey öğrendim.
Mad Physicist

9

C ++ 11 kullanabiliyorsanız std::functionve usinganahtar kelime kullanmak isteyebilirsiniz .

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;

1
C ++ olmadan 11 usingkelime gibi olurdu typedef std::function<void(int, std::string)> FunctionFunc;birisi 11 C ++ olmadan fonksiyonları etrafında başka sarmalayıcı istediği her ihtimale karşı,
En Usta

2
#include <stdio.h>
#include <math.h>

/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/

// typedef a primitive data type
typedef double distance;

// typedef struct 
typedef struct{
    int x;
    int y;
} point;

//typedef an array 
typedef point points[100]; 

points ps = {0}; // ps is an array of 100 point 

// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)

// prototype a function     
distance findDistance(point, point);

int main(int argc, char const *argv[])
{
    // delcare a function pointer 
    distanceFun_p func_p;

    // initialize the function pointer with a function address
    func_p = findDistance;

    // initialize two point variables 
    point p1 = {0,0} , p2 = {1,1};

    // call the function through the pointer
    distance d = func_p(p1,p2);

    printf("the distance is %f\n", d );

    return 0;
}

distance findDistance(point p1, point p2)
{
distance xdiff =  p1.x - p2.x;
distance ydiff =  p1.y - p2.y;

return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}

1
Hangi koşullar altında '&' gereklidir? Örneğin, 'func_p = & findDistance' ve 'func_p = findDistance' eşit derecede iyi çalışıyor mu?
Donna

1
İşlev adı bir işaretçidir, bu nedenle onunla '&' kullanmanıza gerek yoktur. Başka bir deyişle, '&' işlev işaretçileri göz önüne alındığında isteğe bağlıdır. Ancak, ilkel veri türü için adresini almak için '&' işaretini kullanmanız gerekir.
Amjad

1
'&' Nin isteğe bağlı olabileceği her zaman tuhaf olmuştur. Bir ilkel işaretçi oluşturmak için bir typedef kullanılıyorsa (yani typedef (*double) p, '&' isteğe bağlı mıdır?
Donna

Sanırım typedef double* pikiye bir işaretçi tanımlamak için yazmak istediniz . pİşaretçiyi ilkel bir değişkenden doldurmak istiyorsanız , '&' işaretini kullanmanız gerekir. Bir yan not, biz bir işaretçi serbest bırakmak için * <işaretçi adı>. *İşaretçi (fonksiyon adı) çözümlemesi ve fonksiyon komutları bulunur bellek bloğu gitmek için işlev işaretçisi olarak kullanılır.
Amjad

2

Genel sözdizimi durumu için ANSI C standardının A ekine bakabilirsiniz .

Oradan Backus-Naur formunda typedef, bunun türüne sahip olduğunu görebilirsiniz storage-class-specifier.

Türünde declaration-specifierssize önemli değildir sırası birçok belirteci türlerini karıştırabilirsiniz görebilirsiniz.

Örneğin,

long typedef long a;

türü atakma ad olarak tanımlamak için long long. Bu nedenle, kapsamlı kullanımdaki typedef'i anlamak için sözdizimini tanımlayan bazı backus-naur formuna başvurmanız gerekir (ANSI C için sadece ISO'nun değil, birçok doğru gramer vardır).

Bir işlev türü için bir diğer ad tanımlamak için typedef'i kullandığınızda, diğer adı işlevin tanımlayıcısını koyduğunuz yere koymanız gerekir. Sizin durumunuzda, türü FunctionFunc, arama sırasında tür denetimi devre dışı bırakılan ve hiçbir şey döndürmeyen bir işaretçinin çalışması için takma ad olarak tanımlarsınız .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.