c中回调注册函数中的userdata有什么用?

2024-01-06

在注册回调函数中有两个参数。一是函数指针,二是userdata.

int callback_register(fn_ptr cb, void *userdata);
//fn_ptr is typedef

回调期间相同userdata作为参数发回。 我了解发送函数指针的用途,但不了解发送userdata。 谁能告诉我这是如何使用的吗?


如果您拥有的只是指向回调函数的函数指针,则无法将额外的数据传递到回调函数中。

例如,假设我有一些字符串想要使用qsort。我可能会从一些像这样的简单代码开始:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define Sizeofarray(a) (sizeof(a) / sizeof(*a))

int compar(const void *, const void *);

int main()
{
    char *data[] = { "apple", "pear", "1", "2", "10" };
    int i;

    printf("unsorted:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);

    qsort(data, Sizeofarray(data), sizeof(*data), compar);

    printf("\nsorted:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);
}

int compar(const void *p1, const void *p2)
{
    const char *s1 = *(const char **)p1;
    const char *s2 = *(const char **)p2;
    return strcmp(s1, s2);
}

该程序运行良好,并打印:

unsorted:
apple
pear
1
2
10

sorted:
1
10
2
apple
pear

但这是按字母顺序排序,使用strcmp。假设我想要按数字排序的选项(即,像标准的 Unix/Linuxsort命令及其-n选项)。此外,假设我真的想让它成为一个选项,由运行时变量控制。我可以编写一个新的、稍微复杂的比较函数,如下所示:

int compar2(const void *p1, const void *p2)
{
    const char *s1 = *(const char **)p1;
    const char *s2 = *(const char **)p2;

    if(numeric)
         return atoi(s1) > atoi(s2);
    else return strcmp(s1, s2);
}

随着numeric标志设置为 true,输入现在排序为

apple
pear
1
2
10

(这些词首先出现是因为atoi将它们“转换”为 0。)

但接下来的关键问题是,那在哪里numeric旗帜从何而来?如果我拥有的只是qsort和一个不接受用户指定上下文的回调函数,我别无选择,只能使numeric标记一个全局变量:

int numeric;

int main()
{
    char *data[] = { "apple", "pear", "1", "2", "10" };
    int i;

    printf("unsorted:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);

    numeric = 0;
    qsort(data, Sizeofarray(data), sizeof(*data), compar2);

    printf("\nsorted alphabetically:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);

    numeric = 1;
    qsort(data, Sizeofarray(data), sizeof(*data), compar2);

    printf("\nsorted numerically:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);
}

这也有效。但当然没有人喜欢全局变量。

这就是“userdata”参数的概念出现的地方。我不知道它有多标准,但我的系统提供了一个qsort变体称为qsort_r。 (这 ”r”代表“可重入”。)在这个版本中,比较函数传递了一个额外的参数,我可以用它做任何我想做的事情。在这里,我可以将它作为一个指向我的numeric旗帜,现在是我的numericflag 不必是全局变量:

int compar3(void *, const void *, const void *);

int main()
{
    char *data[] = { "apple", "pear", "1", "2", "10" };
    int i;
    int numeric;

    printf("unsorted:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);

    numeric = 0;
    qsort_r(data, Sizeofarray(data), sizeof(*data), &numeric, compar3);

    printf("\nsorted alphabetically:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);

    numeric = 1;
    qsort_r(data, Sizeofarray(data), sizeof(*data), &numeric, compar3);

    printf("\nsorted numerically:\n");
    for(i = 0; i < Sizeofarray(data); i++) printf("%s\n", data[i]);
}

int compar3(void *userdata, const void *p1, const void *p2)
{
    int numeric = *(int *)userdata;
    const char *s1 = *(const char **)p1;
    const char *s2 = *(const char **)p2;

    if(numeric)
         return atoi(s1) > atoi(s2);
    else return strcmp(s1, s2);
}

因此,简而言之,“回调函数中用户数据参数的用途是什么?”这个问题的答案是“这样调用函数就不必使用全局变量将额外的上下文信息传递到它们的回调函数中。”


脚注:在这种情况下,我本可以采取不同的方法。我可以定义两个不同的compar函数,一种用于字母数据,一种用于数字。我可以将一个函数或另一个函数传递给qsort, 像这样:

qsort(data, Sizeofarray(data), sizeof(*data), numeric ? compar_num : compar_alph);

这样我就不需要userdata指针,或qsort_r,或者是一个全局变量。但我希望这个例子能够展示如何userdata指针很有用,以及如何使用它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c中回调注册函数中的userdata有什么用? 的相关文章

  • 在C语言中使用“void”

    我很困惑为什么我们需要通过void转换为 C 函数 int f void return 0 versus int f return 0 什么是正确的做法以及为什么 In C int f 是一种老式的声明 它说f需要固定但未指定数量和类型的参
  • ASP.NET MVC 中的经典 ASP (C#)

    我有一个应用程序想要 最终 转换为 ASP NET MVC 我想要进行全面的服务升级 到 ASP NET 但想要使用当前的 ASP 内容来运行当前的功能 这样我就可以在对新框架进行增量升级的同时升级小部分 该站点严重依赖于不太成熟的 VB6
  • OpenCv读/写视频色差

    我试图简单地使用 openCV 打开视频 处理帧并将处理后的帧写入新的视频文件 我的问题是 即使我根本不处理帧 只是打开视频 使用 VideoCapture 读取帧并使用 VideoWriter 将它们写入新文件 输出文件看起来比输入更 绿
  • asp.net 文本框文本模式数字,仅允许数字

    我只是想知道 ASP NET 中是否有一种方法只允许文本框中的数字textmode number 当我使用这个时
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 当前的 c++ 工作草案与当前标准有何不同

    通过搜索该标准的 PDF 版本 我最终找到了这个链接C 标准措辞草案 http www open std org jtc1 sc22 wg21 docs papers 2012 n3376 pdf从 2011 年开始 我意识到我可以购买最终
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • 如何从网站下载 .EXE 文件?

    我正在编写一个应用程序 需要从网站下载 exe 文件 我正在使用 Visual Studio Express 2008 我正在使用以下代码 private void button1 Click object sender EventArgs
  • 基于xsd模式生成xml(使用.NET)

    我想根据我的 xsd 架构 cap xsd 生成 xml 文件 我找到了这篇文章并按照说明进行操作 使用 XSD 文件生成 XML 文件 https stackoverflow com questions 6530424 generatin
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 尚未处理时调用 Form 的 Invoke 时出现 ObjectDisposeException

    我们得到一个ObjectDisposedException从一个电话到Invoke在尚未处理的表格上 这是一些演示该问题的示例代码 public partial class Form2 Form void Form2 Load object
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 剪贴板在 .NET 3.5 和 4 中的行为有所不同,但为什么呢?

    我们最近将一个非常大的项目从 NET Framework 3 5 升级到 4 最初一切似乎都工作正常 但现在复制粘贴操作开始出现错误 我已经成功制作了一个小型的可复制应用程序 它显示了 NET 3 5 和 4 中的不同行为 我还找到了一种解
  • 运算符“==”不能应用于“int”和“string”类型的操作数

    我正在编写一个程序 我想到了一个数字 然后计算机猜测了它 我一边尝试一边测试它 但我不断收到不应该出现的错误 错误是主题标题 我使用 Int Parse 来转换我的字符串 但我不知道为什么会收到错误 我知道它说 不能与整数一起使用 但我在网
  • 使用 CSharpCodeProvider 类编译 C# 7.3 的 C# 编译器版本是什么?

    我想使用 Microsoft CSharp CSharpCodeProvider 类来编译 C 7 3 代码 编译器版本在 IDictionary 中指定 在创建新的 CSharpCodeProvider 时将其作为输入 例如 Compil
  • 使用 Crypto++ 获取 ECDSA 签名

    我必须使用 Crypto 在变量中获取 ECDSA 签名 我在启动 SignMessage 后尝试获取它 但签名为空 我怎样才能得到它 你看过 Crypto wiki 吗 上面有很多东西椭圆曲线数字签名算法 http www cryptop
  • 匿名结构体作为返回类型

    下面的代码编译得很好VC 19 00 23506 http rextester com GMUP11493 标志 Wall WX Za 与VC 19 10 25109 0 标志 Wall WX Za permissive 这可以在以下位置检

随机推荐

  • 表单随机提交为 GET 而不是 POST

    这有点疯狂 这是我们的表格OpenID 提供商 https blog stackoverflow com 2011 05 stack exchange is an openid provider
  • Ehcache复制缓存启动时不同步

    我有一个跨两台机器复制的 ehcache 缓存 一旦两个对等点启动 对等点就会正确地找到彼此并进行复制 但是 如果第一个对等点首先启动并接收多个元素 然后第二个对等点稍后启动 第二个对等点永远不会看到在它尚未存在时添加的元素 具体顺序如下
  • 如何确认 TrueType PDF 字体缺少字形

    我有一个 PDF 它在 Acrobat 中渲染良好 但在打印机 RIP 上的 PDF 到 PS 转换过程中无法打印 用 pdftk 解压缩并编辑后 我发现如果我替换某种字体的使用 它将打印 该字体是一种奇怪的字体 是带有单个字符 空格 的
  • 正则表达式 - 从给定字符串中提取子字符串

    我这里有一根绳子 This is a string AAA123456789 所以这里的想法是提取字符串AAA123456789使用正则表达式 我正在将其与 X Path 合并 注 如果有相关帖子 请引导我查看 我认为 按理说 我应该sub
  • 如果我的套接字已连接且未关闭,为什么我要发送 RST?

    我有一个 Android 设备 它使用 java net Socket 与 PC 进行无线通信 一切都很好 但如果我在 1 分钟内什么都不做 即没有使用网络 那么当 Android 向 PC 发送数据包时 PC 会收到它并发送 ACK 但
  • IE11 是否有“Backface-visibility:hidden”替代方案?

    我正在尝试让卡片在 IE11 中看起来像在 Google Chrome 中一样 所以我正在寻找 翻转时正面图像不会显示在背面 翻转卡片背面后 背面的文字可见 但正面看不到 它在 IE 中也不起作用 该卡可在 Google Chrome 中使
  • 以编程方式使用自动布局约束

    我正在尝试以编程方式在我的 iOS 应用程序中使用自动布局 我有一个带有此初始化代码的简单视图控制器 UIView innerView UIView alloc initWithFrame self view bounds UIButton
  • 如何通过通话听筒扬声器播放AVSpeechSynthesizer?

    我喜欢通过呼叫接收器扬声器播放音频 目前我正在使用它来播放一些文本作为音频 AVSpeechUtterance utterance AVSpeechUtterance speechUtteranceWithString strTextChe
  • Android L SoundPool.load() 回归

    在 Android L 最新的开发者预览版 Nexus 5 上 SoundPool load 方法似乎存在回归 需要 gt 5 秒才能加载样本 我尝试了 OGG 或 MP3 结果相同 尝试了不同的大小 但都在 100kb 以下 看来40kb
  • 如何在既没有 CORS 也没有 JSONP 的来源的网页上使用 JSON? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 无法跟踪实体类型 Model 的实例,因为已跟踪具有相同 {'Id'} 键值的另一个实例

    我有一个问题 我什么时候会更新我的数据库 我有这个异常 无法跟踪实体类型 ExpenseReport 的实例 因为 另一个具有相同键值 Id 的实例已被使用 被跟踪 附加现有实体时 确保只有一个实体 附加具有给定键值的实例 考虑使用 DbC
  • mysql中STR_TO_DATE解析

    我正在尝试解析 06 01 2010 15 00 00 08 00 问题是最后一个偏移小时 mysqlstr to date无法解析它 有什么想法吗 您需要使用CONVERT TZ函数 http dev mysql com doc refm
  • 未解决的参考:Kotlin 中的 BuildConfig

    所以我开始了一个新的android应用程序 这是我的 Android Studio 信息 Android Studio 3 6 1 Build AI 192 7142 36 36 6241897 built on February 27 2
  • WPF 加载微调器

    目标是显示应用程序正在运行的信息 因此 我正在寻找使用 WPF MVVM 的加载旋转器的智能实现示例 一个非常简单的 即插即用 旋转器可能是来自Font Awesome Wpf 包 https github com charri Font
  • 使用putExtra()向Activity传输大量数据;

    应用程序传递大量对象 解析后大约150个对象 JSON格式 通过intent putExtra 其中有serialized对象 而打开一个新的activity的过程大约需要2秒 有没有办法加快这个过程 如果您只想将数据从一个活动传递到另一个
  • R/dplyr:如何在数据框中仅保留整数?

    我有一个包含多年的数据框 数据类型chr Years 5 yrs 10 yrs 20 yrs 4 yrs 我只想保留整数来获取像这样的数据框 数据类型num Years 5 10 20 4 我如何在 R 中执行此操作 您需要提取数字并将它们
  • 在调试 Java 代码时,@ 在 {Instance@789} 或 "SomeThread"@321: RUNNING 等语句中意味着什么? [复制]

    这个问题在这里已经有答案了 The seems to be everywhere when I debug They are always preceded by some instance variable name and follow
  • 从列名称中删除部分字符串[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 那是一个数据 structure list Fasta headers c Person01050 1 Person01
  • Win32 上的 LAPACK

    我一直在探索需要对矩阵进行一些处理的算法 并且我已经在我的 Linux 机器上获得了一些简单的代码 以下是摘录 extern C link w LAPACK extern void dpptrf const char uplo const
  • c中回调注册函数中的userdata有什么用?

    在注册回调函数中有两个参数 一是函数指针 二是userdata int callback register fn ptr cb void userdata fn ptr is typedef 回调期间相同userdata作为参数发回 我了解