青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

huangyi5209

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  0 Posts :: 13 Stories :: 0 Comments :: 0 Trackbacks

常用鏈接

留言簿

我參與的團隊

搜索

  •  

最新評論

Introduction

If you are reading this article, you probably wonder what callback functions are. This article explains what callback functions are, what are they good for, why you should use them, and so forth. However, before learning what callback functions are, you must be familiar with function pointers. If you aren't, consult a C/C++ book or consider reading the following:

What Is a Callback Function?

The simple answer to this first question is that a callback function is a function that is called through a function pointer. If you pass the pointer (address) of a function as an argument to another, when that pointer is used to call the function it points to it is said that a call back is made.

Why Should You Use Callback Functions?

Because they uncouple the caller from the callee. The caller doesn't care who the callee is; all it knows is that there is a callee with a certain prototype and probably some restriction (for instance, the returned value can be int, but certain values have certain meanings).

If you are wondering how is that useful in practice, imagine that you want to write a library that provides implementation for sorting algorithms (yes, that is pretty classic), such as bubble sort, shell short, shake sort, quick sort, and others. The catch is that you don't want to embed the sorting logic (which of two elements goes first in an array) into your functions, making your library more general to use. You want the client to be responsible to that kind of logic. Or, you want it to be used for various data types (ints, floats, strings, and so on). So, how do you do it? You use function pointers and make callbacks.

A callback can be used for notifications. For instance, you need to set a timer in your application. Each time the timer expires, your application must be notified. But, the implementer of the time'rs mechanism doesn't know anything about your application. It only wants a pointer to a function with a given prototype, and in using that pointer it makes a callback, notifying your application about the event that has occurred. Indeed, the SetTimer() WinAPI uses a callback function to notify that the timer has expired (and, in case there is no callback function provided, it posts a message to the application's queue).

Another example from WinAPI functions that use callback mechanism is EnumWindow(), which enumerates all the top-level windows on the screen. EnumWindow() iterates over the top-level windows, calling an application-provided function for each window, passing the handler of the window. If the callee returns a value, the iteration continues; otherwise, it stops. EnumWindows() just doesn't care where the callee is and what it does with the handler it passes over. It is only interested in the return value, because based on that it continues its execution or not.

However, callback functions are inherited from C. Thus, in C++, they should be only used for interfacing C code and existing callback interfaces. Except for these situations, you should use virtual methods or functors, not callback functions.

A Simple Implementation Example

Now, follow the example that can be found in the attached files. I have created a dynamic linked library called sort.dll. It exports a type called CompareFunction:

typedef int (__stdcall *CompareFunction)(const byte*, const byte*);

which will be the type of your callback functions. It also exports two methods, called Bubblesort() and Quicksort(), which have the same prototype but provide different behavior by implementing the sorting algorithms with the same name.

void DLLDIR __stdcall Bubblesort(byte* array,
                                 int size,
                                 int elem_size,
                                 CompareFunction cmpFunc);

void DLLDIR __stdcall Quicksort(byte* array,
                                int size,
                                int elem_size,
                                CompareFunction cmpFunc);

These two functions take the following parameters:

  • byte* array: a pointer to an array of elements (doesn't matter of which type)
  • int size: the number of elements in the array
  • int elem_size: the size, in bytes, of an element of the array
  • CompareFunction cmpFunc: a pointer to a callback function with the prototype listed above

The implementation of these two functions performs a sorting of the array. But, each time there is a need to decide which of two elements goes first, a callback is made to the function whose address was passed as an argument. For the library writer, it doesn't matter where that function is implemented, or how it is implemented. All that matters it is that it takes the address of two elements (that are the two be compared) and it returns one of the following values (this is a contract between the library developers and its clients):

  • -1: if the first element is lesser and/or should go before the second element (in a sorted array)
  • 0: if the two elements are equal and/or their relative position doesn't matter (each one can go before the other in a sorted array)
  • 1: if the first element is greater and/or should go after the second element (in a sorted array)

With this contract explicitly stated, the implementation of the Bubblesort() function is this (for Quicksort(), which a little bit more complicated, see the attached files).

void DLLDIR __stdcall Bubblesort(byte* array,
                                 int size,
                                 int elem_size,
                                 CompareFunction cmpFunc)
{
   for(int i=0; i < size; i++)
   {
      for(int j=0; j < size-1; j++)
      {
         // make the callback to the comparison function
         if(1 == (*cmpFunc)(array+j*elem_size,
                  array+(j+1)*elem_size))
         {
            // the two compared elements must be interchanged
            byte* temp = new byte[elem_size];
            memcpy(temp, array+j*elem_size, elem_size);
            memcpy(array+j*elem_size,
                   array+(j+1)*elem_size,
                   elem_size);
            memcpy(array+(j+1)*elem_size, temp, elem_size);
            delete [] temp;
         }
      }
   }
}
Note: Because the implementation uses memcpy(), these library functions should not be used for types other than POD (Plain-Old-Data).

On the client side, there must be a callback function whose address is to be passed to the Bubblesort() function. As a simple example, I have written a function that compares two integer values and one that compares two strings:

int __stdcall CompareInts(const byte* velem1, const byte* velem2)
{
   int elem1 = *(int*)velem1;
   int elem2 = *(int*)velem2;

   if(elem1 < elem2)
      return -1;
   if(elem1 > elem2)
      return 1;

   return 0;
}

int __stdcall CompareStrings(const byte* velem1, const byte* velem2)
{
   const char* elem1 = (char*)velem1;
   const char* elem2 = (char*)velem2;

   return strcmp(elem1, elem2);
}

To put all these to a test, I have written this short program. It passes an array with five elements to Bubblesort() or Quicksort() along with the pointer to the callback functions.

int main(int argc, char* argv[])
{
   int i;
   int array[] = {5432, 4321, 3210, 2109, 1098};

   cout << "Before sorting ints with Bubblesort\n";
   for(i=0; i < 5; i++)
      cout << array[i] << '\n';

   Bubblesort((byte*)array, 5, sizeof(array[0]), &CompareInts);

   cout << "After the sorting\n";
   for(i=0; i < 5; i++)
      cout << array[i] << '\n';

   const char str[5][10] = {"estella",
                            "danielle",
                            "crissy",
                            "bo",
                            "angie"};

   cout << "Before sorting strings with Quicksort\n";
   for(i=0; i < 5; i++)
      cout << str[i] << '\n';

   Quicksort((byte*)str, 5, 10, &CompareStrings);

   cout << "After the sorting\n";
   for(i=0; i < 5; i++)
      cout << str[i] << '\n';

   return 0;
}

If I decide that I want the sorting to be done descending (with the biggest element first), all I have to do is to change the callback function code, or provide another that implements the desired logic.

Calling Conventions

In the above code, you can see the word __stdcall in the function's prototype. Because it starts with a double underscore, it is, of course, a compiler-specific extension, more exactly a Microsoft-specific one. Any compiler that supports development of Win32-based applications must support this or an equivalent one. A function that is marked with __stdcall uses the standard calling convention so named because all Win32 API functions (except the few that take variable arguments) use it. Functions that follow the standard calling convention remove the parameters from the stack before they return to the caller. This is the standard convention for Pascal. But in C/C++, the calling convention is that the caller cleans up the stack instead of the called function. To enforce that a function uses the C/C++ calling convention, __cdeclmust be used. Variable argument functions use the C/C++ calling convention.

Windows adopted the standard calling convention (Pascal convention) because it reduces the size of the code. This was very important in the early days of Windows, when it ran on systems with 640 KB RAM.

If you don't like the word __stdcall, you can use the CALLBACK macro, defined in windef.h, as

#define CALLBACK    __stdcall

or

#define CALLBACK    PASCAL

where PASCAL is #defined as __stdcall.

You can read more about calling convention here: Calling Convetions in Microsoft Visual C++.

C++ Methods as Callback Functions

Because you probably write in C++, you want your callback function a method of a class. But, if you try this:

class CCallbackTester
{
public:
   int CALLBACK CompareInts(const byte* velem1, const byte* velem2);
};

Bubblesort((byte*)array, 5, sizeof(array[0]),
           &CCallbackTester::CompareInts);

with a MS compiler, you get this compilation error:

error C2664: 'Bubblesort' : cannot convert parameter 4 from 'int (__stdcall CCallbackTester::*)(const unsigned char *,const unsigned char *)' to 'int (__stdcall *)(const unsigned char *,const unsigned char *)' There is no context in which this conversion is possible

That happens because non-static member functions have an additional parameter, pointer this (see thisFAQ for more).

That obliges you to make the member function static. If that's not acceptable, you can use several techniques to overcome that. Check the following links to learn more.

Notices

The attached files contain two projects. SortingDLL is a Win32 DLL project. The sort.dll output library exports the two sorting functions, Bubblesort() and Quicksort(). The second project, SortDemo, is a Win32 Console Application that demonstrates how to use the sort.dll library. The output directory for both projects is Shared directory, where the following files can be found: sort.h, sort.dll, sort.lib, and SortDemo.exe.

Further References

About the Author

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.

Downloads

  • callbacks.zip
  • posted on 2011-01-24 20:26 huangyi5209 閱讀(804) 評論(0)  編輯 收藏 引用 所屬分類: C/C++
    青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            美女网站在线免费欧美精品| 国产精品久久久久久久久久ktv| 久久精品一区二区三区不卡牛牛| 久久精品国产一区二区电影| 亚洲精品护士| 日韩午夜免费| 极品中文字幕一区| 欧美国产日韩一区二区| 影音先锋另类| 亚洲激情视频网站| 亚洲成色777777女色窝| 影音国产精品| 在线不卡视频| 亚洲精品一区二区三区在线观看| 亚洲黄色免费| 99精品久久免费看蜜臀剧情介绍| 亚洲精品孕妇| 亚洲一区二区网站| 午夜精品美女自拍福到在线 | 欧美国产先锋| 免费黄网站欧美| 久久综合中文字幕| 欧美日韩精品免费观看| 欧美日韩a区| 欧美午夜视频一区二区| 国产在线视频欧美| 亚洲国产一区二区精品专区| 卡通动漫国产精品| 欧美激情va永久在线播放| 欧美成人激情视频免费观看| 国产精品家教| 一区精品久久| 在线播放亚洲一区| 欧美一区二区国产| 免费在线亚洲欧美| 99精品视频免费观看视频| 亚洲综合99| 老司机免费视频一区二区三区| 欧美日韩亚洲综合在线| 国产伦精品一区二区三区免费迷| 亚洲国产影院| 亚久久调教视频| 欧美成人一区二区| 欧美在线观看一区二区| 男女精品网站| 国产日韩精品一区二区三区| 在线观看国产成人av片| 亚洲一区二区网站| 亚洲福利国产| 久久成人18免费网站| 国产精品乱人伦一区二区| 红桃视频成人| 亚洲一二三四久久| 亚洲精品在线观| 久久久久天天天天| 一区精品在线播放| 久久狠狠婷婷| 一区二区三区www| 欧美紧缚bdsm在线视频| 国产综合久久久久影院| 久久国产日本精品| 在线视频欧美日韩| 蜜臀久久99精品久久久画质超高清| 国内精品亚洲| 久久精品一区四区| 久久精品男女| 国产日韩欧美在线播放不卡| 另类春色校园亚洲| 国外成人性视频| 欧美一区二区三区在线观看| 一卡二卡3卡四卡高清精品视频| 欧美国产视频一区二区| 亚洲韩日在线| 亚洲国产高清视频| 午夜精品亚洲| 国产精品网站在线播放| 在线播放精品| 久久久综合网站| 欧美一区二区三区精品| 国产乱人伦精品一区二区 | 久热这里只精品99re8久| 亚洲国产精品久久久久| 欧美日韩国产美女| 夜夜嗨av一区二区三区免费区| 日韩午夜av| 亚洲欧洲在线一区| 欧美先锋影音| 洋洋av久久久久久久一区| 亚洲精选成人| 国产精品久久久久久av福利软件| 一区二区精品国产| 亚洲砖区区免费| 国产一区二区按摩在线观看| 免费一区二区三区| 欧美本精品男人aⅴ天堂| 欧美剧在线观看| 久久成人羞羞网站| 欧美专区在线观看一区| 亚洲人成人77777线观看| 91久久国产综合久久| 国产精品免费在线| 久久亚洲影院| 欧美国产精品日韩| 亚洲欧美色一区| 欧美一区二区播放| 一区二区三区欧美| 亚洲午夜成aⅴ人片| 欧美国产日韩一区| 久久免费一区| 欧美日本一道本| 免费在线播放第一区高清av| 欧美bbbxxxxx| 久久婷婷久久一区二区三区| 久久中文久久字幕| 国产麻豆精品theporn| 欧美国产视频一区二区| 欧美日韩国产三级| 嫩草成人www欧美| 欧美天堂亚洲电影院在线观看| 牛夜精品久久久久久久99黑人| 欧美日韩中文精品| 欧美一乱一性一交一视频| 欧美日本亚洲韩国国产| 久热精品在线视频| 国产有码在线一区二区视频| 亚洲免费成人| av不卡免费看| 麻豆成人小视频| 国产精品自在欧美一区| 亚洲高清免费在线| 国内久久婷婷综合| 香蕉成人久久| 99精品视频免费全部在线| 久久中文精品| 欧美在线免费视频| 欧美天堂在线观看| 亚洲成人在线网| 欧美影院成人| 蜜桃av久久久亚洲精品| av成人免费观看| 欧美久久在线| 欧美激情一区二区三区四区| 精品51国产黑色丝袜高跟鞋| 亚洲欧美精品在线观看| 欧美与黑人午夜性猛交久久久| 欧美高清在线观看| 欧美二区在线播放| av成人国产| 欧美久久久久久| 欧美大成色www永久网站婷| 一本色道久久加勒比88综合| 亚洲国产欧美一区| 久久国产精品久久久久久| 久久久久久久97| 国产欧美三级| 久久久久久亚洲综合影院红桃| 欧美一区二区黄色| 亚洲男人的天堂在线aⅴ视频| 亚洲视频在线观看| 欧美激情精品久久久六区热门| 亚洲精品123区| 99精品欧美一区二区三区| 欧美午夜精品久久久| 日韩午夜免费| 久久激情综合| 国精品一区二区| 欧美国产欧美综合 | 欧美激情自拍| 国产日韩精品一区二区| 久久欧美肥婆一二区| 久热精品在线视频| 99热在这里有精品免费| 欧美精品一区二区三区蜜桃| 亚洲欧美成人| 麻豆成人在线观看| aa成人免费视频| 国产精品成人播放| 亚洲乱码国产乱码精品精天堂| 性欧美大战久久久久久久久| 国产欧美日韩综合一区在线播放| 欧美大尺度在线| 中文欧美字幕免费| 欧美激情视频免费观看| 一本综合久久| 在线观看福利一区| 欧美高清在线视频观看不卡| 亚洲综合三区| 麻豆精品在线视频| 国产欧美一区二区精品性| 免费久久99精品国产自| 亚洲精品在线观看免费| 欧美国产高潮xxxx1819| 亚洲午夜国产成人av电影男同| 激情成人亚洲| 欧美日韩日本网| 欧美成人午夜视频| 亚洲自拍都市欧美小说| 亚洲毛片在线观看.| 久久久久9999亚洲精品| 国产精品视频xxx|