问题描述
我的一项任务使我失去宝贵的时间而没有成功。我必须从作为void * c传递给函数的结构中读取内容。我可以毫无问题地读取其内容,但该字段是指向另一个结构的指针。示例代码:
import SwiftUI
struct TestCountdown: View {
@State var first = 5
@State var second = 5
@State var totalDuration = 30
var body: some View {
vstack {
Text("\(totalDuration)")
if (first > 0) && (second > 0) {
HStack {
TestCode(number: $first,title: "First")
Spacer()
TestCode(number: $second,title: "Second")
}
}
}
.onAppear {
Timer.scheduledTimer(withTimeInterval: 1.0,repeats: true) { _ in
if self.totalDuration > 0 {
self.totalDuration -= 1
if self.first > 0 {
self.first -= 1
} else {
self.second -= 1
}
}
}
}
}
}
struct TestCode: View {
@Binding var number: Int
@State var title: String
var body: some View {
vstack {
Text(title)
.font(.system(size: 20,weight: .medium,design: .rounded))
Text("\(number)")
.font(.system(size: 30,design: .rounded))
}
.frame(minWidth: 50,maxWidth: .infinity)
}
}
我无法阅读的部分是设施名称和设施城市。我知道我可以使用->轻松访问,但是作业要求精确地了解如何在内存中定义结构,并使用void *直接提取其内容。谢谢。
解决方法
作业要求精确地了解如何在内存中定义结构
内存布局(假设没有填充)如下所示。
-------------------------|
| ^ |
c ------> | year | sizeof(int) |
| v |
|------------------------|
| type |
|------------------------|
| free |
|------------------------| |--------| |---|---|---
| facility | ------> | name | -------> | a | b | ..
|------------------------| |--------| |---|---|---
| city | ---\
|--------| | |---|---|---
\---> | x | y | ..
|---|---|---
要访问c->facility->city
,例如:
void *facility = *(void **)( (char *)c + 3 * sizeof(int) ); // skip past year,type,free
void *city = *(void **)((char *)facility + sizeof(char *)); // skip past name
[ EDIT ]。如果没有“ 不填充”的假设,则代码可以使用offsetof
宏。
void *facility = *(void **)( (char *)c + offsetof(struct Car,facility) );
,
在给定指向void *
的结构时,访问该结构的常用方法是将其转换为正确的类型:
void test(void *p)
{
Car *c = p;
printf("Year %d\n",c->year);
printf("Type %d\n",c->type);
printf("Free %d\n",c->free);
printf("Facility name %s\n",c->facility->name);
printf("Facility city %s\n",c->facility->city);
}
请注意,由于您没有返回任何值,因此我将test
的返回类型更改为void
。在调用它之前,还应该使用void test(void *);
对其进行声明。
如果不允许将指针转换为正确的类型,则可以使用int
中定义的offsetof
计算<stddef.h>
成员的位置。如有必要,您也可以在通过其他方式发现偏移后填写偏移。
但是,要访问facility
成员,我们遇到了有关C规则的问题,如下面的注释中所述。我认为严格遵守C语言并没有完全定义的方法。在这种情况下,这是一个错误的分配。
void test(void *p)
{
char *c = p;
printf("Year %d\n",* (int *) (c + offsetof(Car,year)));
printf("Type %d\n",type)));
printf("Free %d\n",free)));
// Set f to point to the location of facility within the Car structure.
char *f = c + offsetof(Car,facility);
/* Unfortunately,although we know f points to a pointer to the structure
containing the name and the city,that structure has no tag,so we
cannot write a cast to it. Instead,we use "(struct Car **)" to say f
points to a pointer to a struct Car. It does not,but the C standard
requires that all pointers to structures have the same representation
and alignment requirements. This is dubious C code,but I see no
alternative given the problem constraints.
Then we dereference that pointer to a structure and convert it to a
pointer to a char,so we can do address arithmetic. Again,since we
have no name for the facility structure,we cannot reference its
members using offsetof. Normal C implementations will not add padding
between members of the same type,so we calculate an offset using the
size of a "char *" and hope that works.
*/
f = (char *) (* (struct Car **) f);
printf("Name %s.\n",* (char **) (f + 0));
printf("City %s.\n",* (char **) (f + sizeof(char *)));
}