指向未知或不完整结构的指针

时间:2017-11-12 16:06:08

标签: c pointers struct

这个问题是对Why is it valid to define a type as pointer to an undefined struct in C?

中问题概念的检验

我知道这不是一个有用的程序,请弃权说“你没有定义这个和那个”。讨论是关于opaque类型的指针aritmethic。很抱歉打扰了太多人,但无论如何答案都很有用。

这个程序:

struct st1 {
  int   a,b;
};

struct st2;

typedef struct st2 *foo;
typedef struct foo *bar;

void main(void) {
  struct st1    *net=0;
  foo   ft1=0;
  bar   test=0;

  net++;
  ft1++;
  test++;
}

使用gcc编译时给出以下内容:

pc:~$ cc tmp2.c
tmp2.c: In function 'main':
tmp2.c:17:6: error: increment of pointer to unknown structure
   ft1++;
      ^
tmp2.c:17:3: error: arithmetic on pointer to an incomplete type
   ft1++;
   ^
tmp2.c:18:7: error: increment of pointer to unknown structure
   test++;
       ^
tmp2.c:18:3: error: arithmetic on pointer to an incomplete type
   test++;
   ^

我想更好地了解这里发生了什么,因为当不知道指针指向什么时,指针aritmethic有点困难......

5 个答案:

答案 0 :(得分:2)

通过声明,您已通知编译器您在程序中有struct st2,但尚未对其进行定义。那种承诺编译器的定义将在稍后出现。

但是你没有在任何地方定义它。

阅读here关于声明和定义之间的区别。

按照函数原型的思路思考。

void fun(int);

你说一个函数fun返回void并且int位于某处。如果您不在程序中调用此功能,则不会造成任何伤害。

但是如果你确实调用它,你必须在某处定义它,比如

void fun(int a)
{ ... }

此处struct的情况类似。如果您没有使用struct st2(和struct foo)类型的变量或其typedef个名称,那么就不会有任何错误。

但是如果你使用它们,必须定义它们,以便编译器知道应该做什么。

答案 1 :(得分:1)

您错过了struct st2的定义。你只需要一个声明告诉编译器这样的结构存在,但你没有告诉编译器结构成员是什么,所以编译器不知道如何做任何取决于知道大小或成员的操作结构。执行ft1++时,您告诉编译器将ft1指针增加结构st2的大小,这是未知的。

同样适用于struct foo

答案 2 :(得分:1)

给出代码

foo

struct st2 can be considered an "opaque structure"twitter_ids_filename = 'all_ids.json' id_selector = '.time a.tweet-timestamp' tweet_selector = 'li.js-stream-item' ids = [] for day in range(days): d1 = format_day(increment_day(start, 0)) d2 = format_day(increment_day(start, 1)) url = form_url(d1, d2) print(url) print(d1) driver.get(url) sleep(delay) try: found_tweets = driver.find_elements_by_css_selector(tweet_selector) increment = 10 while len(found_tweets) >= increment: print('scrolling down to load more tweets') driver.execute_script('window.scrollTo(0, document.body.scrollHeight);') sleep(delay) found_tweets = driver.find_elements_by_css_selector(tweet_selector) increment += 10 print('{} tweets found, {} total'.format(len(found_tweets), len(ids))) for tweet in found_tweets: try: id = tweet.find_element_by_css_selector(id_selector).get_attribute('href').split('/')[-1] ids.append(id) except StaleElementReferenceException as e: print('lost element reference', tweet) except NoSuchElementException: print('no tweets on this day') 是指向不透明结构的指针。每个维基百科:

  

在计算机科学中,不透明数据类型是具体的数据类型   数据结构未在接口中定义。这强制执行   信息隐藏,因为它的值只能被操纵   调用有权访问缺少信息的子例程。该   该类型的具体表示是对其用户隐藏的   可见的实施是不完整的。

如果没有结构细节,你已经注意到它无法进行指针运算。

答案 3 :(得分:1)

指向“opaque类型”的指针的主要用途仅仅是从库例程(或类似)例程接收它并将其传递给其他例程。因此,人们不需要对这些类型进行算术运算。

例如,有人可能会调用一个例程,说“准备从这个文件中读取内容。它将使用格式X格式化,子元素长度为Z,我将使用它们计算P,Q和R.“作为响应,例程设置一些缓冲区,准备一些表来帮助解析,并计算计算P,Q和R所需的一些数字。“该例程返回指向你的指针。

对你来说,那个指针是不透明的;你不知道它指向的是什么结构。对于例程,它是一个非常特定的结构,在库中定义并与其他库例程共享。

稍后,您调用另一个执行实际工作的例程,并将指针传递给它。其他库例程知道结构的定义,因此它可以使用其中的所有内容。

这样做的一个优点是库的未来版本可以更改结构的定义。由于您的程序永远不会看到定义,因此不能依赖它。因此,如果库想要添加功能或改变内部工作方式,它可以改变结构的定义。然后您的源代码不需要重新编译。当它与新版本的库链接时,新库将使用新结构。

答案 4 :(得分:-2)

所有内容都以对此答案的回复发表评论开始:Why is it valid to define a type as pointer to an undefined struct in C? 并且真的没有必要制造这样的混乱。无论如何,我回答我的问题,以便更好地澄清并提供更多信息。 我不是C大师,所以我的术语可能不精确。

最初的问题是为什么声明指向不存在的结构的指针的C程序可以正确编译。 为了缩短它,这是因为这种方式可以使用不透明类型,可以使用的类型 不太了解他们(所以程序员不能摆弄他们的内容)。这是一个很好的C技巧, 尤其用于图书馆; C语言在标识符可见性和这个技巧上并不出色 以某种方式克服了这种限制。

原始问题的答案之一表明,这样的指针(那些指向不透明类型的指针)与其他指针并没有什么不同。 这个陈述并不完全正确,我的评论("指针运算怎么样?")只是打响报警。

嗯,原始问题的答案是,声明(通过typedef)指向未声明的指针不是错误 结构,并且声明具有该类型的变量都不是错误。但尝试以某种方式使用这种类型是错误的 (需要了解该类型背后的真实数据的那些)。

老实说,C语言的行为不是最大的一致性,而我想到的唯一原因是,因为 你可以声明不透明的类型。这些opaque类型仅在单独的编译单元(尤其是库)的上下文中有用。 同样,C方式单独编译单元特定于C,并不完美。

通过陈述"声明必须被定义",出现了一些微妙的错误思想。我们想要不透明的数据吗? 然后不能完成不完整的声明。因此,在指向不透明数据的指针上无法进行某些操作。

在本页顶部问题中发布的程序中,有一个完全引用的typedef声明 不存在的结构(" struct foo")。这是另一点:可以让typedef引用不完整的结构, 但提到不存在的更为奇怪。当然必须有一个很好的理由:嘿,C是C。