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

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>
            夜色激情一区二区| 国产精品成人观看视频国产奇米| 国产亚洲欧美激情| 欧美v日韩v国产v| 99在线精品免费视频九九视| 久久久蜜桃一区二区人| 亚洲精品一区二区三区av| 国产精品视频专区| 欧美成人免费全部| 美女视频黄 久久| 欧美三级日本三级少妇99| 亚洲天堂成人| 91久久精品www人人做人人爽| 久久午夜av| 亚洲美女尤物影院| 久久久久在线| 久久国产精品久久久久久电车| 亚洲视屏在线播放| 一本综合久久| 亚洲视频一区在线| 亚洲美女淫视频| 亚洲美女黄色| 一本色道久久综合亚洲精品小说| 亚洲精品一二三区| 亚洲精品影院| 91久久视频| 欧美黄色大片网站| 久久午夜激情| 亚洲永久网站| 亚洲一区尤物| 最新国产乱人伦偷精品免费网站 | 午夜久久久久久久久久一区二区| 国产精品久久久久久久久借妻| 国产精品久久久久一区二区| 欧美精品网站| 久久久久成人精品| 欧美喷潮久久久xxxxx| 欧美日韩国产一区二区| 国产精品久久久久毛片软件| 国产亚洲a∨片在线观看| 精品999网站| 99国产精品| 欧美一区成人| 欧美成人资源网| 亚洲视频axxx| 欧美专区18| 欧美人妖在线观看| 国产精品久久影院| 伊人成年综合电影网| 亚洲精品国产视频| 欧美一级片在线播放| 六月婷婷久久| 一区二区三区国产精华| 欧美一区二区日韩一区二区| 美玉足脚交一区二区三区图片| 久久人人97超碰国产公开结果| 亚洲永久精品大片| 午夜在线精品偷拍| 亚洲第一在线| 狂野欧美激情性xxxx| 老司机免费视频久久| 国产视频一区欧美| 欧美亚洲一级片| 亚洲免费综合| 国产有码一区二区| 性欧美大战久久久久久久免费观看 | 亚洲二区在线| 欧美激情精品久久久久久黑人| 国产精品久久午夜| 亚洲女与黑人做爰| 亚洲美女在线国产| 国产精自产拍久久久久久| 久久久久高清| 欧美日韩免费在线观看| 亚洲在线黄色| 先锋亚洲精品| 亚洲品质自拍| 一本色道久久88亚洲综合88| 国产欧美日韩不卡免费| 免费在线欧美黄色| 欧美日韩高清在线| 久久噜噜噜精品国产亚洲综合| 欧美日韩国产页| 亚洲一区二区三区国产| 欧美激情一区二区三区四区| 欧美日韩国产色视频| 久久久久久久久久码影片| 欧美精品一区二区三区久久久竹菊 | 精品91在线| 欧美一区二区在线视频| 日韩亚洲视频| 久久综合久久综合九色| 午夜精品福利视频| 欧美日本一区二区三区| 麻豆成人在线观看| 一本色道**综合亚洲精品蜜桃冫| 欧美激情aaaa| 亚洲国产精品va在线观看黑人| 韩国亚洲精品| 香蕉乱码成人久久天堂爱免费 | 国产免费观看久久黄| 亚洲国产高清一区| 亚洲精品久久久蜜桃| 久久永久免费| 欧美激情一区二区三区成人| 亚洲观看高清完整版在线观看| 亚洲欧美日韩国产综合在线| 亚洲欧美日韩在线| 国产在线播精品第三| 久久国产精品99国产| 亚洲高清免费| 欧美呦呦网站| 亚洲国产高清aⅴ视频| 亚洲人成啪啪网站| 欧美激情网友自拍| 一区二区三区精品视频在线观看| 亚洲综合成人在线| 久久精品中文| 久久久久久久久久久一区| 在线观看福利一区| 欧美日韩国产一区精品一区 | 亚洲精品一区二区在线| 欧美精品亚洲精品| 久久国产一区| 亚洲欧美中文在线视频| 亚洲精选一区二区| 久久亚洲电影| 亚洲综合99| 亚洲视频一区在线| 亚洲国产清纯| 一区精品久久| 国内精品久久久久久久果冻传媒| 欧美日韩一区二区三区免费| 久久另类ts人妖一区二区| 日韩视频在线永久播放| 亚洲人成网站777色婷婷| 亚洲视频免费观看| 欧美成人官网二区| 国产手机视频一区二区| 99精品国产一区二区青青牛奶| 性色av一区二区三区红粉影视| 蜜桃av一区二区在线观看| 一区二区三区国产在线观看| 久久深夜福利免费观看| 国产精品女同互慰在线看| 亚洲乱码日产精品bd| 欧美福利电影在线观看| 亚洲一区日韩在线| 欧美日在线观看| a4yy欧美一区二区三区| 欧美成人一区二区| 久久久久久久综合| 小黄鸭视频精品导航| 久久精品伊人| 久久久久久综合| 在线观看日韩av先锋影音电影院| 欧美一级视频精品观看| 亚洲综合精品自拍| 国产精品久久久亚洲一区| 欧美一区二区三区免费在线看| 日韩视频在线播放| 国产伦精品一区二区三区在线观看| 一区二区av在线| 在线综合亚洲| 有码中文亚洲精品| 欧美岛国激情| 国产精品久久久久国产a级| 亚洲欧美视频在线观看视频| 午夜亚洲福利| 99精品国产热久久91蜜凸| 亚洲一级影院| 亚洲乱码国产乱码精品精| 午夜在线a亚洲v天堂网2018| 黄色日韩在线| 亚洲一区区二区| 亚洲精品你懂的| 久久av一区二区三区亚洲| 亚洲视频欧美视频| 老**午夜毛片一区二区三区| 亚洲网在线观看| 欧美精品一区二区三区在线看午夜 | 亚洲精品专区| 亚洲免费视频中文字幕| 亚洲高清视频在线观看| 午夜精品视频在线观看| 亚洲精品免费观看| 久久久91精品国产一区二区三区| 99精品国产一区二区青青牛奶| 久久精品综合一区| 久久国产高清| 99视频精品| 亚洲精品国产系列| 欧美va亚洲va日韩∨a综合色| 久久亚洲不卡| 韩国三级电影一区二区| 欧美一区二区性| 久久综合色88| 亚洲黄色毛片| 欧美人与性动交cc0o| av不卡在线|