我正在阅读有关iphone音频的教程,它使用的是C/C++.我不熟悉这个 - >的用法.它似乎引用了一个指向全局变量的指针.这是教程 - iPhone核心音频第3部分 - 音频回调.
我试图理解的声明是声明的这一部分:
// Pass in a reference to the phase value, you have to keep track of this
// so that the sin resumes right where the last call left off
float phase = THIS->sinPhase;
Run Code Online (Sandbox Code Playgroud)
该教程表明THIS->用于获取访问AudioController变量.似乎sinPhase是全局变量.
请解释为什么创建"阶段"引用而不是直接引用全局变量"sinPhase".请记住,我是一个客观的C编程,试图理解这个C/C++代码.
在此示例中,THIS不是对全局变量的引用; 它在上面的函数中定义,作为void指针的强制转换inRefCon:
static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
// Get a reference to the object that was passed with the callback
// In this case, the AudioController passed itself so
// that you can access its data.
AudioController *THIS = (AudioController*)inRefCon;
Run Code Online (Sandbox Code Playgroud)
这是C中相当常见的模式; 为了将回调传递给某个API,以便稍后可以调用您的代码,您传递函数指针和void指针.void指针包含函数指针需要操作的任何数据.在回调中,您需要将其强制转换为指向实际类型的指针,以便您可以访问其中的数据.在这种情况下,该示例的作者正在命名该转换指针THIS,可能是为了使它看起来更像面向对象,即使这只是C并且THIS没有特殊含义.
你问为什么他们将它分配给一个局部变量而不是只是THIS->sinPhase在任何地方使用.没有理由不能THIS->sinPhase到处使用; 他们可能只是将它分配给一个局部变量phase来节省打字.优化器很可能在局部变量上做得比在通过指针传入的变量更好,因为它可以对局部变量做出更多假设(特别是,它可以假设没有其他人在更新它同一时间).所以使用局部变量循环可能会稍微快一点,但我不确定没有测试; 最可能的原因是为了节省输入并使代码更具可读性.
这是一个简单的示例,说明这样的回调API如何工作; 希望这样可以更容易理解回调API的工作原理,而无需同时了解Core Audio中剩余的内容.假设我想编写一个将回调应用于整数10次的函数.我可能会写:
int do_ten_times(int input, int (*callback)(int)) {
int value = input;
for (int i = 0; i < 10; ++i) {
value = callback(value);
}
return value;
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以用不同的功能调用该方法,像下面add_one()或times_two():
int add_one(int x) {
return x + 1;
}
int times_two(int x) {
return x * 2;
}
result = do_ten_times(1, add_one);
result = do_ten_times(1, times_two);
Run Code Online (Sandbox Code Playgroud)
但是说我希望能够添加或乘以不同的数字; 我可以尝试为你想要添加或乘以的每个数字编写一个函数,但如果代码中的数字没有修复,但是基于输入你会遇到问题.你不能为每个可能的数字写一个函数; 你将需要传入一个值.所以让我们为回调添加一个值,并将do_ten_times()值传递给:
int do_ten_times(int input, int (*callback)(int, int), int data) {
int value = input;
for (int i = 0; i < 10; ++i) {
value = callback(value, data);
}
return value;
}
int add(int x, int increment) {
return x + increment;
}
int times(int x, int multiplier) {
return x * multiplier;
}
result = do_ten_times(1, add, 3);
result = do_ten_times(1, times, 4);
Run Code Online (Sandbox Code Playgroud)
但是如果有人想编写一个不同于整数的函数呢?例如,如果你想编写一个函数来添加不同的数字,具体取决于输入是负还是正?现在我们需要传入两个值.再次,我们可以扩展我们的接口以传入两个值; 但我们最终需要传递更多的价值观,不同类型的价值观等.我们注意到我们do_ten_times真正关心的是我们传入的价值的类型; 它只需要将它传递给回调,并且回调可以解释它喜欢它.我们可以使用void指针实现这一点; 然后回调将该void指针强制转换为适当的类型以获取值:
int do_ten_times(int input, int (*callback)(int, void *), void *data) {
int value = input;
for (int i = 0; i < 10; ++i) {
value = callback(value, data);
}
return value;
}
int add(int x, void *data) {
int increment = *(int *)data;
return x + increment;
}
int times(int x, void *data) {
int multiplier = *(int *)data;
return x * multiplier;
}
struct pos_neg {
int pos;
int neg;
};
int add_pos_neg(int x, void *data) {
struct pos_neg *increments = (struct pos_neg *)data;
if (x >= 0)
return x + increments->pos;
else
return x + increments->neg;
}
int i = 3;
result = do_ten_times(1, add, &i);
int m = 4;
result = do_ten_times(1, times, &m);
struct pos_neg pn = { 2, -2 };
result = do_ten_times(-1, add_pos_neg, &pn);
Run Code Online (Sandbox Code Playgroud)
当然,这些都是玩具的例子.在Core Audio的情况下,回调用于生成音频数据的缓冲区; 每次音频系统需要生成更多数据以便保持平滑播放时,都会调用它.通过它传递的信息void *inRefCon用于跟踪当前缓冲区中正确波形的确切位置,因此下一个缓冲区可以从最后一个缓冲区中取出.
| 归档时间: |
|
| 查看次数: |
913 次 |
| 最近记录: |