点(“。”)运算符和箭头(“ - >”)运算符在C与Objective-C中使用

时间:2012-01-31 00:12:29

标签: objective-c c pointers dot-operator

我试图围绕C与Objective-C中的使用和语法的一些差异。特别是,我想知道C运算符和Objective-C中的点运算符和箭头运算符的使用方式有何不同(以及原因)。这是一个简单的例子。

C代码:

// declare a pointer to a Fraction
struct Fraction *frac;

...

// reference an 'instance' variable
int n = (*frac).numerator;     // these two expressions
int n = frac->numerator;       // are equivalent

Objective-C代码:

// declare a pointer to a Fraction
Fraction *frac = [[Fraction alloc] init];

...

// reference an instance variable
int n = frac.numerator;        // why isn't this (*frac).numerator or frac->numerator??

那么,看看frac在两个程序中是如何相同的(即它是指向Fraction对象或结构的指针),为什么它们在访问属性时使用不同的语法?特别是在C中,使用numerator访问frac->numerator属性,但使用Objective-C,使用点运算符访问frac.numerator。由于frac是两个程序中的指针,为什么这些表达式不同?任何人都可以帮我澄清一下吗?

5 个答案:

答案 0 :(得分:77)

frac在两个程序中实际上并不相同。

C Fraction是一个struct,它是一个没有重载运算符的基本类型,默认情况下只能构造和销毁。如果在结构上定义函数或字段,则在C中访问这些属性的方法是使用点(.)运算符。当您使用struct时,Objective-C维护此运算符。为方便起见,您可以使用箭头(->)运算符(您提到的两个等效表达式)执行取消引用和点运算。在访问struct时,Objective-C也会保留这一点。

然而,在您的示例中,Objective-C Fraction可能(假设)至少是类型id的指针,它只是一个类名和指向该类实例的指针引擎盖下。它也很可能是NSObjectNSProxy的子类。这些Objective-C类的特殊之处在于它们只在C结构之上有一整层预定义操作(如果你真的想深入研究它,那么你可以看一下Objective-C Runtime Reference )。另外需要注意的是,Objective-C类总是一个指针

最基本的操作之一是objc_msgSend。当我们对这些类型的对象进行操作时,Objective-C编译器将点(.)运算符或方括号语法([object method])解释为objc_msgSend方法调用。有关这里实际发生的更多详细信息,请参阅负责Obj-C运行时开发的Apple工程师Bill Bumgarner的this series of posts

箭头(->)运算符实际上不应该用于Objective-C对象。就像我说的,Objective-C类实例是一个C结构,添加了额外的通信层,但是当您使用箭头时,该层通信基本上被绕过了。例如,如果您打开Xcode并键入[UIApplication sharedApplication]->然后调出方法完成列表,您会看到:

A list of internal ivars on an Obj-C object when using the arrow operator

在这里,您可以看到一堆普通字段,我们通常使用方括号语法(如[[UIApplication sharedApplication] delegate])进行访问。但是,这些特定项是C字段,用于存储各自Objective-C属性的值。

所以,你可以大致这样想:

C对象上的点运算符

  1. (在运行时)字段的返回值
  2. C对象上的箭头操作符(指针)

    1. 取消引用指针
    2. 字段的返回值
    3. Objective-C对象(指针)上的点运算符/方括号

      1. (在编译时)替换为对objc_msgSend
      2. 的调用
      3. (在运行时)查找Obj-C类定义,如果出现错误则抛出异常
      4. 取消引用指针
      5. 字段的返回值
      6. Objective-C对象(指针)上的箭头运算符

        1. (在运行时)取消引用指针
        2. 字段的返回值
        3. 现在我肯定在这里过于简单了,但总结一下:在两种情况下,箭头运算符看起来基本相同,但点运算符在Objective-C中有额外/不同的含义。

答案 1 :(得分:9)

Dot-notation是一种设计选择。由于我们总是处理指向objc实例的指针,我猜设计师想要一些熟悉的东西,这也不会破坏现有的程序。它是在几年前的ObjC 2中引入的。在此之前,您总是必须使用括号进行消息传递。

点符号虽然有所不同 - 它不是直接访问,而是消息

那是:

obj.property = val;
// is the same as:
[obj setProperty:val];
// and not:
obj->property = val;


val = obj.property;
// is the same as:
val = [obj property];
// and not:
val = obj->property;

您仍然可以编写obj->ivar来访问指向对象成员的指针(如果可见)。

答案 2 :(得分:6)

在您的第一个示例中,Fraction是一个结构。 在第二个示例中,Fraction是Objective-C类(在iOS中可能是NSObject的子类)。

C ++ does not allow重载operator .。因此,如果没有其他信息,您可以推断出您所看到的点符号是集成到Objective-C中的附加语言构造,而不是C / C ++定义或重载的运算符。

实际上,点符号只是实现者选择作为属性访问速记的设计特征,完全等同于方括号getter:

myObjCVar.prop == [myObjCVar prop];

答案 3 :(得分:2)

对象上的点运算符是用于访问对象属性的特殊语法。它在幕后调用属性的getter或setter。因此,例如,[@"hello" length]@"hello".length相同*。对于所有其他类型,点与C点相同,箭头始终相同。

*注意:访问者方法的名称并不总是与属性相同。如果它是声明的属性并且声明指定了一个特殊的getter或setter方法,那么将使用该方法。

答案 4 :(得分:1)

C中的点和箭头符号与Objective-C(严格超集)中的相同。我认为需要区分的根本区别在于struct和Objective-C对象之间的区别。

Objective-C中用于对象的点表示法用于Objective-C 2.0中引入的属性。但是,对于结构, - > Objective-C和C之间的点符号是相同的。