- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在学习有关 iPhone 音频的教程,它使用 C/C++。我不熟悉 THIS-> 的使用。它似乎指的是指向全局变量的指针。这是教程 - iPhone Core Audio Part 3 – Audio Callback 。
我试图理解的语句是语句的 THIS-> 部分:
// 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;
教程指出 THIS-> 用于获取访问 AudioController 变量。看来sinPhase是全局变量。
请解释为什么创建“phase”引用,而不是直接引用全局变量“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;
这是 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;
}
现在我可以使用不同的函数来调用它,例如下面的 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);
但是假设我希望能够对不同的数字进行加法或乘法;我可以尝试为您想要相加或相乘的每个数字编写一个函数,但是如果代码中的数字没有固定,而是基于输入,那么您就会遇到问题。你不能为每个可能的数字编写一个函数;您将需要传递一个值。因此,让我们向回调添加一个值,并让 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);
但是如果有人想编写一个随整数以外的值变化的函数怎么办?例如,如果您想编写一个函数,根据输入是负数还是正数来添加不同的数字,该怎么办?现在我们需要传入两个值。同样,我们可以扩展我们的接口(interface)以传入两个值;但我们最终需要传入更多的值、不同类型的值等等。我们注意到 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);
当然,这些都是玩具示例。在Core Audio情况下,回调用于生成音频数据的缓冲区;每次音频系统需要生成更多数据以保持流畅播放时都会调用它。通过 void *inRefCon
传递的信息用于跟踪当前缓冲区中正弦波的准确位置,以便下一个缓冲区可以从上一个缓冲区停止的位置开始。
关于objective-c - 在 C/C++ 中使用 THIS->,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13533842/
我是一名优秀的程序员,十分优秀!