这个问题是对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有点困难......
答案 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。