我有头文件String.h
typedef struct String String;
typedef String* String_t;
...
struct String {
//... other methods
void (*push_str)(String_t self, void *str); ???
}
void string_push_cstr(String_t self, char * str);
void string_push_slice(String_t self, Slice_t str);
void string_push_string(String_t self, String_t str);
#define string_push_str(self, str) _Generic(str, \
char*: string_push_cstr, \
String_t: string_push_string, \
Slice_t: string_push_slice \
)(self, str);
是否有可能以某种方式使用相同的 API 和编译时验证将这样一个通用的 Push_str 函数添加到我的 String 结构中? (无联合类型或其他参数)
我最近的尝试是使用这种令人难堪的黑客
#define push_str(self, str) dummy();_Generic(str, \
char*: string_push_cstr, \
String_t: string_push_string, \
Slice_t: string_push_slice \
)(self, str);
dummy 基本上是 String 结构中的 nop 函数指针 所以在预处理之后我做了同样的事情,但是有额外的空调用
我不确定我是否理解您想用这 3 个函数编写的内容,但我将向您展示一个带有代码和输出的玩具示例,并就该主题编写一些参数。
C
语言:
class
,所以没有类instance
java
或 C++
private
中没有
struct
#values
课程那样的javascript
this
中没有
struct
void*,
和 void**
NULL
终止数组可以做很多多态的事情C++
,甚至还差得远。C
“类”如果您想像类一样看到
String
,但有所有限制,您可以使用函数指针数组,并在函数签名中进行一些标准化。 void*
返回接受 void**
参数 NULL
终止的函数将很难阅读和维护,但这是可能的。
如果函数签名不同,那么数组的想法就消失了......
用 OOP 术语来说,我们需要的最少方法是:
String
String
toString()
方法,如 java
中所示,打印出 String
,以便我们可以轻松测试我会写一些额外的内容:
slice()
方法,类似于 javascript 数组类中的方法,它返回原始 String
的切片。empty()
方法,如果字符串为空,则返回 0
。struct
代表 String
考虑这个
typedef struct st_S String;
typedef struct st_S
{
size_t size; // size
char* S; // the array
String* (*destroy)(String*);
String* (*copy)(const String*);
String* (*slice)(const String*, unsigned, unsigned);
int (*show)(const String*, const char*);
int (*empty)(const String*);
void** elements;
} String;
所有方法都使用
String*
,因为 this
中没有 C
指针。它肯定会破坏事情,因为代码无法确保指针引用 String
的同一个实例。
无论如何,对于这个我们可以声明一个构造函数,比如
String* so_create(
const char* source, String* destroy(String*),
String* copy(const String*),
String* slice(const String*, unsigned, unsigned),
int show(const String*, const char*),
int empty(const String*));
并编写其他方法的一个或多个实现。
main.c
在 String
所以,如果我们编写这个方法,那么
main
的代码应该可以工作(并调用所有方法):
#include <stdio.h>
#include "stuff.h"
int main(void)
{
String* one = so_create(
"Stack Overflow", so_destroy, so_copy, so_slice,
so_show, so_empty);
if (one == NULL)
{ fprintf(stderr, " Error creating string\n");
return -1; }
one->show(one, NULL);
String* other = one->copy(one);
one->show(other, "A simple copy ");
other = other->destroy(other);
other = one->slice(one, 1, 14);
other->show(other, "slice(1,14) ");
other = other->destroy(other);
other = one->slice(one, 0, 1);
other->show(other, "slice(0, 1) ");
if (other->empty(other))
printf("Previous slice was empty\n");
else
printf(
"Previous slice was not empty: size is %llu\n",
other->size);
other = other->destroy(other);
one = one->destroy(one);
return 0;
}
代码注释:
slice(a,b)
类似于 javascript
数组,返回原始的开放式子字符串,从索引 a
到但不包括 b
。我没有将其实现为负值。show
接受可选前缀以帮助测试,因此不需要混乱的 printf
调用。destroy
返回 NULL
并用于使同一行中的 String
指针无效。 [15] "Stack Overflow"
A simple copy [15] "Stack Overflow"
slice(1,14) [14] "tack Overflow"
slice(0, 1) [2] "S"
Previous slice was not empty: size is 2
#include <stdio.h>
typedef struct st_S String;
typedef struct st_S
{
size_t size; // size
char* S; // the array
String* (*destroy)(String*);
String* (*copy)(const String*);
String* (*slice)(const String*, unsigned, unsigned);
int (*show)(const String*, const char*);
int (*empty)(const String*);
void** elements;
} String;
String* so_create(
const char* org, String* destroy(String*),
String* copy(const String*),
String* slice(const String*, unsigned, unsigned),
int show(const String*, const char*),
int empty(const String*));
String* so_copy(const String*);
String* so_destroy(String*);
int so_empty(const String*);
int so_show(const String*, const char*);
String* so_slice(const String*, unsigned, unsigned);
int so_empty(const String*);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stuff.h"
String* so_destroy(String* this)
{
if (this == NULL) return NULL;
if (this->S != NULL) free(this->S);
free(this);
return NULL;
}
int so_empty(const String* this) { return this->size == 0; }
int so_show(const String* this, const char* prefix)
{
if (this == NULL) return -1;
if (prefix != NULL) printf("%s", prefix);
printf(" [%llu] \"%s\"\n", this->size, this->S);
return 0;
}
String* so_create(
const char* src, String* destroy(String*),
String* copy(const String*),
String* slice(const String*,unsigned,unsigned),
int show(const String*, const char*),
int empty(const String*))
{
String* nw = malloc(sizeof(String));
if (nw == NULL) return NULL;
if (src == NULL)
{
nw->size = 0;
nw->S = NULL;
return nw;
}
nw->size = 1+strlen(src);
nw->S = malloc(nw->size);
if (nw->S == NULL)
{
free(nw);
return NULL;
}
char* dst = nw->S;
for (size_t i = 0; i < nw->size; i += 1)
*dst++ = *src++;
nw->destroy = destroy;
nw->copy = copy;
nw->slice = slice;
nw->show = show;
nw->empty = empty;
return nw;
}
String* so_copy(const String* this)
{
if (this == NULL) return NULL;
return so_create(
this->S, this->destroy, this->copy, this->slice,
this->show, this->empty);
}
String* so_slice(const String* this, unsigned start, unsigned end)
{
if (this == NULL) return NULL;
if (end <= start) return NULL;
if (end > this->size - 1)
return so_create(
NULL, this->destroy, this->copy, this->slice,
this->show, this->empty);
size_t sz = end - start; // size of slice
char tmp = *(this->S+end);
*( (this->S) + end ) = 0;
String* copy = so_create(
(this->S)+start, this->destroy, this->copy, this->slice,
this->show, this->empty);
*((this->S) + end) = tmp;
return copy;
}
这可以具有某种形式的多态性,因为我们可以为除
create()
之外的任何方法提供许多实现。
但它只是一个玩具。希望它能以某种方式有所帮助。