一个静态库,可以通过void *
接收任何结构,并且能够访问它的成员变量,无论是嵌入式结构还是指向函数的指针。
它保证作为嵌入式结构的成员变量将在那里并且可以通过super
访问,并且一个成员变量是一个名为execute
的函数指针。
问题 - (简而言之,如何仅使用void *
访问基础结构成员)
我猜它与通用编程有关,我们是否可以通过内存地址或任何其他替代方式访问以下内容。 在编译时无法转换为特定结构 struct肯定会有一个执行指针函数和超级变量。保证。
// from src/library.c (someStruct a void *, casting to specific struct is not available)
someStruct->execute();
someStruct->super->execute();
尝试1 Reference
struct Super *pointer = someStruct + 8; // works
pointer->execute(); // prints overridden method!
// how to access second member which is a pointer to function
对任何形式的解决方案开放,无论它是低级别还是内存地址,以访问每个成员或任何其他替代方式。
预期输出:
重写方法!
超级方法
的src / library.h
#ifndef POLY_LIBRARY_H
#define POLY_LIBRARY_H
struct Library {
void (*passSomeStruct)(void *someStruct);
};
struct Library *newLibrary();
#endif
的src / LIBRARY.C
#include "library.h"
#include <stdlib.h>
void passSomeStruct(void *someStruct) {
// can we somewhow access the following via memory addresses or any other alternate way.
// casting to specific structure is not available at compile time
// struct will sure have an execute pointer function and super variable
someStruct->execute();
someStruct->super->execute();
}
struct Library *newLibrary() {
struct Library *library = malloc(sizeof(struct Library));
library->passSomeStruct = passSomeStruct;
return library;
}
的src / super.h
#ifndef POLY_SUPER_H
#define POLY_SUPER_H
struct Super {
void (*execute)();
};
struct Super *newSuper();
#endif //POLY_SUPER_H
的src / super.c
#include "super.h"
#include <stdio.h>
#include <stdlib.h>
static void execute() {
printf("super method\n");
}
struct Super *newSuper() {
struct Super *super = malloc(sizeof(struct Super));
super->execute = execute;
return super;
}
测试
测试/ library_test.h
#ifndef POLY_LIBRARY_TEST_H
#define POLY_LIBRARY_TEST_H
#endif //POLY_LIBRARY_TEST_H
测试/ library_test.c
#include "../src/library.h"
#include "temp.h"
int main() {
struct Library *library = newLibrary();
struct Temp *temp = newTemp();
library->passSomeStruct(temp);
return 0;
}
测试/ temp.h
#ifndef TEST_SUPER_H
#define TEST_SUPER_H
#include <stdlib.h>
struct Temp {
struct Super *super;
void (*execute)();
};
struct Temp *newTemp();
#endif //TEST_SUPER_H
测试/ temp.c
#include "temp.h"
#include <stdio.h>
#include "../src/super.h"
static void execute() {
printf("overridden method!\n");
}
struct Temp *newTemp() {
struct Temp *temp = malloc(sizeof(struct Temp));
temp->super = newSuper();
temp->execute = execute;
return temp;
}
生成文件
VPATH := src test
all: libTest
libTest: super.o library.o
mkdir -p bin
ar rcs bin/libTest $^
test: library_test
./library_test
library_test: library_test.o library.o super.o temp.o
$(CC) -o $@ $^
%.o: %.c %.h
答案 0 :(得分:1)
我担心我不能给你一个如何完成OOP的完美例子 C,无论如何都不会在几分钟之内成为我的头顶。还有其他 Stack Overflow中的这些内容更详细,就像这样 之一:
Can you write object-oriented code in C?
我强烈建议您阅读该主题,那里有很多好的答案。
我还建议,如果您真的想在代码库中使用OOP,请不要
自己写,它非常复杂,非常耗时。在那里面
我会建议您使用GObject
作为代码的一部分
glib
库。{我告诉你这一切,因为你说的评论
是的,这是我需要了解更多的部分,我不太了解该域,字节布局,转换为
char*
等。
当它出现这样的事情时,了解这些事情是至关重要的。
我将在评论中给出一个非常简短的例子 内存布局等
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#define TEND 0
#define TINT 1
#define TSTRING 2
#define TDOUBLE 3
typedef struct typeinfo {
int type;
size_t offset;
} TypeInfo;
typedef struct K1 {
int a;
int b;
char c[32];
} K1;
void print_K1(K1 *obj)
{
printf("K1: %d %s %d\n", obj->a, obj->c, obj->b);
}
TypeInfo *init_k1(K1 *obj, int a, int b, const char *c)
{
TypeInfo *types = calloc(4, sizeof *types);
obj->a = a;
obj->b = b;
strcpy(obj->c, c);
// filling type info
// we know the structure, we can provide this information
types[0].type = TINT;
types[0].offset = offsetof(K1, a);
types[1].type = TINT;
types[1].offset = offsetof(K1, b);
types[2].type = TSTRING;
types[2].offset = offsetof(K1, c);
types[3].type = TEND;
return types;
}
typedef struct K2 {
int k;
double o;
} K2;
void print_K2(K2 *obj)
{
printf("K2: %d %lf\n", obj->k, obj->o);
}
TypeInfo *init_k2(K2 *obj, int k, double o)
{
TypeInfo *types = calloc(3, sizeof *types);
obj->k = k;
obj->o = o;
// filling type info
// we know the structure, we can provide this information
types[0].type = TINT;
types[0].offset = offsetof(K2, k);
types[1].type = TDOUBLE;
types[1].offset = offsetof(K2, o);
types[2].type = TEND;
return types;
}
void somefunc(void *ptr, TypeInfo *types)
{
char *base = ptr, *offset;
while(1)
{
offset = base + types->offset;
switch(types->type)
{
case TINT:
{
int *p = (int*) offset;
*p *= -1;
break;
}
case TSTRING:
{
char *p = offset;
p[0] = ' ';
break;
}
case TDOUBLE:
{
double *p = (double*) offset;
*p *= 0.35;
}
case TEND:
return;
}
types++;
}
}
int main(void)
{
K1 k1;
K2 k2;
TypeInfo *t1, *t2;
t1 = init_k1(&k1, 33, -23, "Hello Peter");
print_K1(&k1);
somefunc(&k1, t1);
print_K1(&k1);
t2 = init_k2(&k2, 112, 122.12);
print_K2(&k2);
somefunc(&k2, t2);
print_K2(&k2);
free(t1);
free(t2);
return 0;
}
我有两个不同成员的结构K1
和K2
,这意味着他们的记忆
布局不同。对于K1
和K2
,有使用的{init}函数
helper struct TypeInfo
存储结构成员的偏移量和类型
他们自己的班级。这些信息已知,因此他们可以构建
这样的信息表。 offsetof
返回字段成员的偏移量
从结构类型的开始。
函数somefunc
对结构没有任何了解,所以它不能
将void
指针强制转换为结构的指针。然而它得到了一个列表
来自呼叫者的类型。此函数会更改每个int
成员的符号,
用每个字符串替换带有空字符的第一个字母
将每两倍乘以0.35
。感谢types
,它可以获得成员
使用types
提供的偏移量。
main
函数初始化每个结构的一个对象,打印原始对象
state,用对象和类型信息调用somefunc
并打印出来
对象再次。在输出中,您可以看到值已更改
相应
<强>输出强>
K1: 33 Hello Peter -23
K1: -33 ello Peter 23
K2: 112 122.120000
K2: -112 42.742000
虽然这可行,但我认为这不是一个优雅的解决方案。这是一个
基本的例子,但在处理更复杂的事情时会变得非常复杂
结构。这将向您展示如何访问您所在的结构的内容
只有一个void
指针。但没有类型信息,这不可能
完成。出于这个原因,我鼓励你使用一些已经存在的库
实施了打字系统。 GObject
非常成熟,广泛用于GTK +应用程序。
Glib和GTK +人们多年来一直在使用它,所以我会相信他们的
实施任何自我实施的解决方案。
答案 1 :(得分:0)
最后我把它揭秘了,但是我可以接受建议,任何人都可以改进这个答案,让它变得更好或者向我解释这里发生了什么?
它是某种神奇的数字8,可以解决问题。
void passSomeStruct(void *someStruct) {
struct Super *pointer = someStruct + 8;
pointer->execute(); // outputs "overridden method!"
pointer = someStruct + 16;
pointer->execute(); // outputs "super method"
}
修改强>
我的结构定义,我想知道为什么首先定义的super
是16偏移量,我定义的方法execute
是8偏移量,分配的内存是反向的而不是我定义了它们?
struct Temp {
struct Super *super;
void (*execute)();
};