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

huangyi5209

  C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
  0 Posts :: 13 Stories :: 0 Comments :: 0 Trackbacks

常用鏈接

留言簿

我參與的團(tuán)隊(duì)

搜索

  •  

最新評(píng)論

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) 評(píng)論(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>
            久久综合狠狠综合久久综合88| 午夜电影亚洲| 久久久99精品免费观看不卡| 久久国内精品视频| 好吊日精品视频| 欧美18av| 亚洲一区二区三区高清| 久久久久青草大香线综合精品| 韩国成人精品a∨在线观看| 国产一区二区黄| 欧美精品导航| 午夜在线精品偷拍| 亚洲人成网站色ww在线| 久久精品免视看| 久久精品主播| 免费在线观看精品| 欧美激情亚洲激情| 国产精品区二区三区日本| 裸体一区二区| 久久精品国产精品亚洲综合| 亚洲第一精品电影| 亚洲欧美日韩综合一区| 亚洲国产成人在线| 国产精品一区毛片| 欧美国产在线电影| 麻豆国产精品777777在线| 欧美激情中文字幕一区二区| 国产精品欧美日韩| 亚洲免费av电影| 亚洲国产精品成人综合色在线婷婷| 最新中文字幕亚洲| 亚洲第一黄色网| 国内精品免费在线观看| 国产精品每日更新| 欧美日韩综合一区| 欧美精品国产精品日韩精品| 国产毛片久久| 国产精品99久久久久久人| 亚洲欧洲精品一区二区| 小辣椒精品导航| 欧美一区二区三区精品| 亚洲尤物视频在线| 亚洲午夜电影网| 亚洲一区在线免费观看| 免费日本视频一区| 老色鬼久久亚洲一区二区| 久热国产精品| 亚洲欧美春色| 久久精品一区二区国产| 国产精品久久网| 亚洲视频二区| 亚洲人成网站色ww在线| 免费观看成人鲁鲁鲁鲁鲁视频 | 欧美电影免费观看大全| 亚洲男人天堂2024| 亚洲四色影视在线观看| 亚洲春色另类小说| 久久男人av资源网站| 一区二区三区免费看| 亚洲午夜精品17c| 亚洲欧美日韩专区| 欧美日韩亚洲高清| 国产欧美 在线欧美| 国产一区二区三区在线观看精品| 亚洲一区二区三区四区五区黄| 欧美国产欧美亚洲国产日韩mv天天看完整 | 日韩午夜电影在线观看| 亚洲图片欧美一区| 欧美日韩亚洲一区| 亚洲午夜电影| 亚洲午夜激情网站| 国产模特精品视频久久久久| 亚洲欧美国产视频| 午夜视频在线观看一区| 国产亚洲欧美色| 麻豆精品在线播放| 美女免费视频一区| 99国产精品久久久久久久| 欧美一区二区三区在线免费观看| 亚洲图片欧美日产| 国产一区二区三区在线观看精品 | 亚洲视频国产视频| 亚洲视频免费在线观看| 久久欧美中文字幕| 欧美午夜a级限制福利片| 国模吧视频一区| 欧美1级日本1级| 香蕉久久一区二区不卡无毒影院 | 久久综合中文色婷婷| 久久综合五月| 亚洲伊人网站| 久久精品中文字幕一区二区三区| 亚洲激情一区二区三区| 亚洲综合三区| 久久精品国产77777蜜臀| 亚洲精品久久久久久下一站| 久久久亚洲一区| 欧美国产视频在线观看| 亚洲欧美一区二区精品久久久| 久久九九电影| 亚洲午夜高清视频| 久久精品一区蜜桃臀影院| 中文日韩电影网站| 久久久久久久波多野高潮日日| 国产精品国产馆在线真实露脸 | 国产精品极品美女粉嫩高清在线 | 一本色道久久综合狠狠躁篇怎么玩| 久久激情五月丁香伊人| 久久全国免费视频| 一区二区三区四区精品| 最新日韩欧美| 欧美成年视频| 亚洲精品中文字幕在线| 国产精品99久久不卡二区| 亚洲盗摄视频| 欧美亚洲日本一区| 国产午夜精品视频免费不卡69堂| 在线综合欧美| 久久深夜福利免费观看| 午夜视频一区二区| 欧美日本二区| 亚洲欧美日韩国产成人精品影院| 久久色在线播放| 久久久久久久久久码影片| 欧美一区二区成人| 亚洲一区日韩| 国产精品v一区二区三区| 亚洲激情第一区| 亚洲国产精品va| 久久精品亚洲乱码伦伦中文| 欧美在线观看你懂的| 国产精品v亚洲精品v日韩精品| 亚洲人成人一区二区三区| 1769国内精品视频在线播放| 久久狠狠亚洲综合| 久久五月激情| 欧美激情中文不卡| 亚洲第一页中文字幕| 在线免费一区三区| 玖玖玖国产精品| 欧美国产成人精品| 亚洲人成网站777色婷婷| 久久在线免费观看| 欧美激情精品久久久久久| 久久夜色精品国产噜噜av| 久久久久久久综合| 韩国在线视频一区| 久久久久亚洲综合| 欧美大片免费观看| 日韩一本二本av| 国产精品成人一区| 亚洲综合国产激情另类一区| 亚洲欧美在线磁力| 国产午夜精品美女视频明星a级 | 久久精品国产成人| 国内揄拍国内精品少妇国语| 欧美在线91| 午夜国产精品视频| 国产精品系列在线| 久久久久久电影| 亚洲国产欧美一区二区三区同亚洲 | 国产亚洲欧美日韩一区二区| 久久精品国产欧美亚洲人人爽| 久热精品在线视频| 99国产精品久久久久老师| 欧美四级电影网站| 欧美专区在线观看| 最新日韩精品| 久久久久成人网| 最新成人av在线| 国产精品jvid在线观看蜜臀 | 久久精品视频va| 亚洲欧洲一区二区在线观看| 亚洲中午字幕| 在线免费观看日本一区| 欧美日韩专区| 久久全球大尺度高清视频| 99伊人成综合| 99综合在线| 国产一区导航| 欧美日韩不卡| 亚洲精品在线电影| 亚洲精品美女久久久久| 国产精品久久久久一区二区三区共| 欧美一区二区啪啪| 日韩视频在线一区二区| 久久中文精品| 亚洲欧美制服另类日韩| 最新国产拍偷乱拍精品| 国产精品日韩久久久久| 欧美成人蜜桃| 久久久久久香蕉网| 亚洲一区视频| 亚洲精品影视在线观看| 嫩草国产精品入口| 久久久91精品国产| 亚洲欧美日韩精品久久久久| 亚洲靠逼com| 尤妮丝一区二区裸体视频| 久久人人精品|