结构内的通用函数指针,具有编译时验证

问题描述 投票:0回答:1

我有头文件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 函数指针 所以在预处理之后我做了同样的事情,但是有额外的空调用

c c-preprocessor
1个回答
0
投票

我不确定我是否理解您想用这 3 个函数编写的内容,但我将向您展示一个带有代码和输出的玩具示例,并就该主题编写一些参数。

C
语言:

  • 没有像其他语言一样的
    class
    ,所以没有类
    instance
  • 没有
    java
    C++
  • 意义上的方法
  • private
     中没有 
    struct
  • 数据
  • 没有像
    #values
    课程那样的
    javascript
  • this
     中没有 
    struct
  • 指针
  • void*,
    void**
    NULL
    终止数组可以做很多多态的事情
  • 不是
    C++
    ,甚至还差得远。
  • 是主力。

A
C
“类”

如果您想像类一样看到

String
,但有所有限制,您可以使用函数指针数组,并在函数签名中进行一些标准化
void*
返回接受
void**
参数
NULL
终止的函数将很难阅读和维护,但这是可能的。

如果函数签名不同,那么数组的想法就消失了......

用 OOP 术语来说,我们需要的最少方法是:

  • 一个 构造函数,返回一个新的
    String
  • 一个析构函数释放所有分配的东西
  • a 复制构造函数 可以方便地返回
    String
  • 的新副本
  • a
    toString()
    方法,如
    java
    中所示,打印出
    String
    ,以便我们可以轻松测试

我会写一些额外的内容:

  • 一个
    slice()
    方法,类似于 javascript 数组类中的方法,它返回原始
    String
    的切片。
  • 一个
    empty()
    方法,如果字符串为空,则返回
    0

a
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

stuff.h:标题

#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*);

stuff.c:可能的实现

#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()
之外的任何方法提供许多实现。

但它只是一个玩具。希望它能以某种方式有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.