Pointed fungsi typedef?

460

Saya belajar cara memuat DLL secara dinamis, tetapi yang tidak saya mengerti adalah baris ini

typedef void (*FunctionFunc)();

Saya punya beberapa pertanyaan. Jika seseorang mampu menjawabnya, saya akan berterima kasih.

  1. Mengapa typedefdigunakan?
  2. Sintaksnya terlihat aneh; setelah itu voidseharusnya tidak ada nama fungsi atau sesuatu? Sepertinya fungsi anonim.
  3. Apakah pointer fungsi dibuat untuk menyimpan alamat memori suatu fungsi?

Jadi saya bingung saat ini; dapatkah kamu mengklarifikasi hal untukku?

Jack Harvin
sumber
5
Lihatlah tautan (bagian terakhir) learncpp.com/cpp-tutorial/78-function-pointers
antusiasngegeek
9
Perlu dicatat bahwa karena c ++ 11 using FunctionFunc = void (*)();dapat digunakan sebagai gantinya. Ini sedikit lebih jelas bahwa Anda hanya mendeklarasikan nama untuk suatu tipe (penunjuk berfungsi)
user362515
hanya untuk menambahkan ke @ user362515, bentuk yang sedikit lebih jelas bagi saya adalah:using FunctionFunc = void(void);
topspin
@topspin IIRC keduanya tidak sama. Salah satunya adalah tipe pointer fungsi, yang lainnya adalah tipe fungsi. Ada konversi implisit, itu sebabnya ia bekerja, IANA (C ++) L jadi, orang dapat masuk dan memperbaiki saya. Bagaimanapun, jika maksudnya adalah untuk menentukan jenis pointer saya pikir sintaks dengan *sedikit lebih eksplisit.
user362515

Jawaban:

463

typedefadalah konstruksi bahasa yang mengaitkan nama ke suatu jenis.
Anda menggunakannya dengan cara yang sama Anda akan menggunakan jenis aslinya, misalnya

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

suka menggunakannya

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

Seperti yang Anda lihat, Anda bisa saja mengganti nama typedefed dengan definisi yang diberikan di atas.

Kesulitan terletak pada pointer ke fungsi sintaksis dan keterbacaan dalam C dan C ++, dan typedefdapat meningkatkan pembacaan deklarasi tersebut. Namun, sintaksinya sesuai, karena fungsi - tidak seperti tipe yang lebih sederhana - mungkin memiliki nilai dan parameter pengembalian, sehingga deklarasi pointer ke fungsi terkadang panjang dan kompleks.

Keterbacaan dapat mulai sangat rumit dengan pointer ke array fungsi, dan beberapa rasa lain yang bahkan lebih tidak langsung.

Untuk menjawab tiga pertanyaan Anda

  • Mengapa typedef digunakan? Untuk memudahkan pembacaan kode - terutama untuk pointer ke fungsi, atau struktur nama.

  • Sintaksnya terlihat aneh (dalam pointer ke pernyataan fungsi) Sintaks itu tidak jelas untuk dibaca, setidaknya ketika mulai. typedefSebaliknya, menggunakan deklarasi memudahkan pembacaan

  • Apakah pointer fungsi dibuat untuk menyimpan alamat memori suatu fungsi? Ya, pointer fungsi menyimpan alamat suatu fungsi. Ini tidak ada hubungannya dengan typedefkonstruk yang hanya memudahkan penulisan / pembacaan suatu program; kompiler hanya perlu memperluas definisi typedef sebelum mengkompilasi kode aktual.

Contoh:

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
e2-e4
sumber
6
dalam contoh terakhir, bukan hanya 'kotak' merujuk ke hal yang sama yaitu pointer ke fungsi alih-alih menggunakan & kuadrat.
pranavk
2
Pertanyaan, dalam contoh typedef pertama Anda, Anda memiliki formulir typedef type aliastetapi dengan pointer fungsi tampaknya hanya ada 2 argumen typedef type,. Apakah alias default ke nama yang ditentukan dalam tipe argumen?
dchhetri
2
@pranavk: Ya, squaredan &square(dan, memang, *squaredan **square) semuanya merujuk ke pointer fungsi yang sama.
Jonathan Leffler
6
@ user814628: Tidak jelas apa yang Anda minta. Dengan typedef int newname, Anda membuat newnamealias untuk int. Dengan typedef int (*func)(int), Anda membuat funcalias untuk int (*)(int)- pointer berfungsi mengambil intargumen dan mengembalikan intnilai.
Jonathan Leffler
10
Saya kira saya hanya bingung tentang pemesanan. Dengan typedef int (*func)(int), saya mengerti bahwa func adalah alias, hanya sedikit bingung karena alias kusut dengan tipenya. Pergi dengan typedef int INTsebagai contoh saya akan lebih kemudahan jika typedef fungsi pointer adalah bentuk typedef int(*function)(int) FUNC_1. Dengan begitu saya bisa melihat tipe dan alias dalam dua token yang terpisah daripada disatukan menjadi satu.
dchhetri
188
  1. typedefdigunakan untuk mengetik alias; dalam hal ini Anda aliasing FunctionFuncuntuk void(*)().

  2. Memang sintaksnya memang terlihat aneh, lihat ini:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
    
  3. Tidak, ini hanya memberitahu kompiler bahwa FunctionFunctipe akan menjadi pointer fungsi, itu tidak mendefinisikan satu, seperti ini:

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"
    
Jacob Relkin
sumber
27
typedeftidak tidak menyatakan jenis baru. Anda dapat memiliki banyak typedefnama yang ditentukan dari jenis yang sama, dan mereka tidak berbeda (mis. wrt. overloading fungsi). ada beberapa keadaan di mana, sehubungan dengan bagaimana Anda dapat menggunakan nama, nama yang typedefdidefinisikan tidak persis sama dengan apa yang didefinisikan, tetapi beberapa typedefnama yang ditetapkan untuk hal yang sama, adalah setara.
Ceria dan hth. - Alf
Ah saya mengerti sekarang. Terima kasih.
Jack Harvin
4
+1 untuk jawaban pertanyaan 2 - sangat jelas. Sisa dari jawabannya juga jelas, tetapi yang menonjol bagi saya :-)
Michael van der Westhuizen
33

Tanpa typedefkata, dalam C ++ deklarasi akan mendeklarasikan variabel FunctionFuncpointer tipe berfungsi tanpa argumen, kembali void.

Dengan typedefitu alih-alih mendefinisikan FunctionFuncsebagai nama untuk tipe itu.

Ceria dan hth. - Alf
sumber
5
Ini adalah cara yang sangat baik untuk memikirkannya. Jika Anda membaca jawaban lain dengan cermat, mereka tidak benar-benar mengatasi kebingungan OP tentang keterjeratan alias dan nama. Saya belajar sesuatu yang baru dari membaca posting ini.
Fisikawan Gila
9

Jika Anda dapat menggunakan C ++ 11, Anda mungkin ingin menggunakan std::functiondan usingkata kunci.

using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
Halil Kaskavalci
sumber
1
tanpa usingkata kunci C ++ 11 akan seperti typedef std::function<void(int, std::string)> FunctionFunc;, kalau-kalau seseorang ingin pembungkus lain di sekitar fungsi tanpa C ++ 11
Top-Master
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) );
}
Amjad
sumber
1
Dalam keadaan apa '&' itu dibutuhkan? Misalnya, apakah 'func_p = & findDistance' dan 'func_p = findDistance' bekerja dengan baik?
Donna
1
Nama fungsi adalah pointer, jadi Anda tidak perlu menggunakan '&' dengannya. Dengan kata lain, '&' adalah opsional ketika fungsi pointer dipertimbangkan. Namun, untuk tipe data primitif Anda perlu menggunakan tanda '&' untuk mendapatkan alamatnya.
Amjad
1
Itu selalu terasa aneh bahwa '&' pernah bisa opsional. Jika typedef digunakan untuk membuat pointer ke primitif (yaitu typedef (*double) p, apakah '&' opsional?
Donna
Saya pikir Anda ingin mengetik typedef double* puntuk menentukan pointer ke ganda. Jika Anda ingin mengisi ppointer dari variabel primitif, Anda harus menggunakan tanda '&'. Sebagai catatan, kami Anda * <nama pointer> untuk dereference pointer. The *digunakan dalam fungsi pointer dereference pointer (nama fungsi) dan pergi ke blok memori di mana instruksi fungsi berada.
Amjad
2

Untuk kasus umum sintaks Anda dapat melihat lampiran A dari standar ANSI C .

Dalam bentuk Backus-Naur dari sana, Anda bisa melihat yang typedefmemiliki tipe storage-class-specifier.

Pada tipe yang declaration-specifiersAnda dapat melihat bahwa Anda dapat mencampur banyak tipe specifier, urutan yang tidak masalah.

Misalnya, benar untuk mengatakan,

long typedef long a;

untuk menentukan jenis asebagai alias untuk long long. Jadi, untuk memahami typedef pada penggunaan lengkap, Anda perlu berkonsultasi dengan beberapa bentuk backus-naur yang mendefinisikan sintaks (ada banyak tata bahasa yang benar untuk ANSI C, tidak hanya yang dari ISO).

Saat Anda menggunakan typedef untuk mendefinisikan alias untuk jenis fungsi, Anda harus meletakkan alias di tempat yang sama tempat Anda meletakkan pengenal fungsi. Dalam kasus Anda, Anda mendefinisikan tipe FunctionFuncsebagai alias untuk penunjuk yang berfungsi yang pemeriksaan tipenya dinonaktifkan saat panggilan berlangsung dan tidak mengembalikan apa pun.

alinsoar
sumber