用C语言将字符串转换为类型

用C语言将字符串转换为类型,c,C,原型:尺寸偏移(类型、构件) 我知道第一个参数是类型,如果字符串中只有名称而不是类型呢。我想获得一个只包含字符串文本的成员的偏移量 我需要社区的帮助,如何做到这一点 例: #包括 #包括 typedef结构示例{ 无效*成员1; 无效*成员2; }榜样; 无符号整型 偏移量_gen(char*ds,char*member) { 返回(抵销(ds,成员)); } 无效的 main() { printf(“\n%d”,offset_gen(“示例”,“成员1”)); printf(“\n%d”,of

原型:
尺寸偏移(类型、构件)

我知道第一个参数是类型,如果字符串中只有名称而不是类型呢。我想获得一个只包含字符串文本的成员的
偏移量

我需要社区的帮助,如何做到这一点

例:

#包括
#包括
typedef结构示例{
无效*成员1;
无效*成员2;
}榜样;
无符号整型
偏移量_gen(char*ds,char*member)
{
返回(抵销(ds,成员));
}
无效的
main()
{
printf(“\n%d”,offset_gen(“示例”,“成员1”));
printf(“\n%d”,offset_gen(“示例”,“成员2”));
}

我认为您使用的
偏移量是错误的。必须将结构类型和成员名称传递给宏,而不是包含其名称的字符串

例如,如果您的结构是:

typedef struct example_ {
    void *member1;
    void *member2;
}example;
然后,您可以计算
member1
的偏移量,如下所示:

offsetof(example, member1)
但是,如果您仍然希望使用现有的字符串文字,则必须手动将
offset\u gen
中的
member
参数与结构成员名称进行比较,并调用相应的宏

例如:

unsigned int
offset_gen(char *ds, char *member)
{
    if(!strcmp(ds,"example"))
    {
        if(!strcmp(member,"member1"))
            return (offsetof(example, member1));
        else if(!strcmp(member,"member2"))
            return (offsetof(example, member2));
    }
    return -1;       // if no match for input paramters is found
}

你甚至可以尝试这样的方法,或者甚至(如果你想测试你的极限!)。

我认为你使用了
offsetof
的错误方法。必须将结构类型和成员名称传递给宏,而不是包含其名称的字符串

例如,如果您的结构是:

typedef struct example_ {
    void *member1;
    void *member2;
}example;
然后,您可以计算
member1
的偏移量,如下所示:

offsetof(example, member1)
但是,如果您仍然希望使用现有的字符串文字,则必须手动将
offset\u gen
中的
member
参数与结构成员名称进行比较,并调用相应的宏

例如:

unsigned int
offset_gen(char *ds, char *member)
{
    if(!strcmp(ds,"example"))
    {
        if(!strcmp(member,"member1"))
            return (offsetof(example, member1));
        else if(!strcmp(member,"member2"))
            return (offsetof(example, member2));
    }
    return -1;       // if no match for input paramters is found
}

你甚至可以尝试这样的方法,或者甚至(如果你想测试你的极限!)。

下面是一个关于如何开始实现这一点的真实示例

注意:这不是应用程序就绪代码。我是白手起家写这篇文章的,因此,它只应被视为概念的证明;在开发团队中用作讨论基础的东西。此版本不使用适当的C解析器,但假定在C源代码中使用某些约定

这篇文章中包含的所有文件都是根据,即专用于公共领域的授权文件。但是,请记住,没有任何保证:如果它损坏或损坏了其他东西,不要怪我

本质上,我们使用Bash+Awk脚本生成一个C程序,在编译和运行时,该程序生成一个包含预计算数据的哈希表,以及一个
member\u offset()
函数,可以用来查找结构类型的成员偏移量,结构类型和成员名称以字符串形式给出

为了便于说明,这是一个完整的工作示例,包括一个
Makefile

文件
mytypes.h
包含我们感兴趣的类型:

#include <stdlib.h>

struct type1 {
    char         one, two[2];
    float        three;
    int        (*callback)(const char *, void *, size_t);
} __attribute__((__packed__));

struct type2 {
    char         four;
    struct type1 five;
    int          six, seven[3];
};
为了构建项目,我们使用
Makefile
。请注意,缩进是制表符,而不是空格;make那样很挑剔

CC      := gcc
CFLAGS  := -Wall -O2
LDFLAGS :=

.PHONY: all clean

all: clean example

clean:
    rm -f *.o example member-offset.c member-offset-generator.c member-offset-generator

member-offset.c: mytypes.h
    rm -f $@ member-offset-generator member-offset-generator.c
    ./member-offset-generator.bash mytypes.h:type1 mytypes.h:type2 > member-offset-generator.c
    $(CC) $(CFLAGS) member-offset-generator.c $(LDFLAGS) -o member-offset-generator
    ./member-offset-generator > $@
    rm -f member-offset-generator member-offset-generator.c

%.o: %.c
    $(CC) $(CFLAGS) -c $^

example: member-offset.o main.c
    $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
注意上面的
成员偏移量.c
规则。它指的是自动生成的C源文件,其中将包含
member\u offset()
函数。如果它还不存在,并且每当修改
mytypes.h
时,都会重新编译它

命令
/member-offset-generator.bash mytypes.h:type1 mytypes.h:type2>member-offset-generator.c
使用尚未显示的第四个文件(见下文),检查
mytypes.h
,并在类型数据库哈希表中包括
struct type1
struct type2
。输出是
member offset generator.c
,这是一个c程序,在编译和运行时,会生成我们实际需要的c代码。将此规则拆分为单独的规则可能更好,但现在,我让它自动编译并运行
member offset generator.c
,然后删除它(因为它只需要输出
member offset.c
一次)

生成中间C程序的shell脚本,
member offset generator.bash
,非常复杂:

#!/bin/bash
export LANG=C LC_ALL=C

[ -n "$CC"     ] || export CC="gcc"
[ -n "$CFLAGS" ] || export CFLAGS="-Wall -O2"

if [ $# -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    exec >&2
    printf '\n'
    printf 'Usage: %s [ -h | --help ]\n' "$0"
    printf '       %s HEADER[:TYPE] ...\n' "$0"
    printf '\n'
    printf 'This script autogenerates a C program, that when run,\n'
    printf 'emits a C implementation of function member_offset()\n'
    printf 'which returns the offset of "member" within type "struct type".\n'
    printf '\n'
    printf 'The generated C program includes all HEADER files,\n'
    printf 'but each one only once. Only the specified struct types\n'
    printf 'will be supported by the final function.\n'
    printf '\n'
    exit 1
fi

function hash_of_function() {
    sed -e 's|        ||' << END
        /* DJB2 xor hash, http://www.cse.yorku.ca/~oz/hash.html */
        size_t hash_of(const void *data, const size_t size)
        {
            const unsigned char       *p = (const unsigned char *)data;
            const unsigned char *const q = (const unsigned char *)data + size;
            size_t                     h = 5381;
            while (p < q)
                h = ((h << 5) + h) ^ (*(p++));
            return h;
        }
END
}

# Emit all headers as includes, but each one only once.
printf '%s\n' "$@" | awk \
   'BEGIN {
        RS="\n"
        FS=":"
        split("", seen)

        printf "#include <stdlib.h>\n"
        printf "#include <stddef.h>\n"
        printf "#include <string.h>\n"
        printf "#include <stdio.h>\n"
        seen["stdlib.h"] = 1
        seen["stddef.h"] = 1
        seen["string.h"] = 1
        seen["stdio.h"] = 1
    }
    {
        header = $1
        sub(/^[<"]/, "", header)
        sub(/[>"]$/, "", header)
        if (length(header) > 0 && !(header in seen)) {
            seen[header] = 1
            if (substr($1, 1, 1) == "<")
                printf "#include <%s>\n", header
            else
                printf "#include \"%s\"\n", header
        }
    }'

# emit the hash function as a string.
printf '\nstatic const char hash_of_def[] =\n'
hash_of_function | sed -e 's|\\|\\\\|g; s|"|\\"|g; s|^|    "|g; s|[\t\v\f ]*$|\\n"|g'
printf '    ;\n\n'
# and the hash function itself.
hash_of_function

# emit structures and code used by the generator itself.
sed -e 's|^    ||' <<END

    struct type_member_list {
        struct type_member_list *next;
        size_t                   offset;
        size_t                   hash;
        size_t                   namelen;
        char                     name[];
    };

    struct type_list {
        struct type_list        *next;
        struct type_member_list *members;
        size_t                   hash;
        size_t                   slots;
        size_t                   typelen;
        char                     type[];
    };

    static size_t type_list_size(const struct type_list *list)
    {
        size_t result = 0;
        while (list) {
            ++result;
            list = list->next;
        }
        return result;
    }

    static size_t type_member_list_size(const struct type_member_list *list)
    {
        size_t result = 0;
        while (list) {
            ++result;
            list = list->next;
        }
        return result;
    }


    static struct type_list *types = NULL;


    static void add_type_member(const char *type, const char *name, const size_t offset)
    {
        const size_t typelen = (type) ? strlen(type) : 0;
        const size_t namelen = (name) ? strlen(name) : 0;

        struct type_list        *list = NULL, *temp;
        struct type_member_list *member;

        if (!typelen || !namelen) {
            if (!typelen)
                fprintf(stderr, "Error: add_type_member() called with empty type.\n");
            if (!namelen)
                fprintf(stderr, "Error: add_type_member() called with empty name.\n");
            exit(EXIT_FAILURE);
        }

        /* Find the list for the specified type. */
        for (temp = types; temp != NULL; temp = temp->next)
            if (temp->typelen == typelen && !strcmp(temp->type, type)) {
                list = temp;
                break;
            } 

        /* If this is a new type, create a new list. */
        if (!list) {
            list = malloc(sizeof (struct type_list) + typelen + 1);
            if (!list) {
                fprintf(stderr, "Error: Out of memory.\n");
                exit(EXIT_FAILURE);
            }
            memcpy(list->type, type, typelen);
            list->type[typelen] = '\0';
            list->typelen = typelen;
            list->hash = hash_of(type, typelen);
            list->slots = 0;
            list->members = NULL;

            /* Prepend to global types list. */
            list->next = types;
            types = list;
        }

        /* Create a new member. */
        member = malloc(sizeof (struct type_member_list) + namelen + 1);
        if (!member) {
            fprintf(stderr, "Error: Out of memory.\n");
            exit(EXIT_FAILURE);
        }
        memcpy(member->name, name, namelen);
        member->name[namelen] = '\0';
        member->namelen = namelen;
        member->hash = hash_of(name, namelen);
        member->offset = offset;

        /* Prepend to member list. */
        member->next = list->members;
        list->members = member;
    }

    void add_types_and_members(void)
    {
END

ignorefirst=$'<"'
ignorelast=$'>"'

# Extract the member names from each structure.
for pair in "$@"; do
    name="${pair#*:}"
    [ ":$name" = ":$pair" ] && continue
    [ -n "$name" ] || continue

    file="${pair%%:*}"
    file="${file#[$ignorefirst]}"
    file="${file%[$ignorelast]}"

    $CC $CFLAGS -P -E "$file" | \
    sed -e '/#/ d' | tr -s '\t\n\v\f\r ' '      ' | \
    sed -e 's|\(struct [^ ]*\) {|\n\1 {\n|g; s|}|\n}\n|g; s| *;|\n|g; s|)([^)]*)||g' | \
    awk -v name="$name" \
   'BEGIN {
        RS = " *\n"
        FS = " *,"
        split("", members)
    }

    $0 == ("struct " name " {") {
        inside = 1
        next
    }

    $0 == "}" {
        inside = 0
        next
    }

    inside {
        for (i = 1; i <= NF; i++) {
            member = $i
            sub(/\[[^\[\]]*\]/, "", member)
            sub(/^.*[ \*(]/, "", member)
            if (!(member in members))
                members[member] = member
        }
    }

    END {
        for (member in members)
            printf "    add_type_member(\"%s\", \"%s\", offsetof(struct %s, %s));\n", name, member, name, member
    }' || exit 1
done

# emit the rest of the generator code.
sed -e 's|^    ||' <<END
    }

    size_t type_slots(struct type_list *list)
    {
        const size_t  size = type_list_size(list);
        const size_t  max_slots = 4 * size + 1;
        size_t        slots = size;
        size_t       *used, i, n;

        struct type_list *item;

        used = malloc(max_slots * sizeof used[0]);
        if (!used) {
            fprintf(stderr, "Error: Out of memory.\n");
            exit(EXIT_FAILURE);
        }

        while (1) {
            if (slots >= max_slots) {
                fprintf(stderr, "Error: Weak hash function; hash table grows too large.\n");
                fprintf(stderr, "       (Need more than %zu slots for %zu data entries.)\n", max_slots, size);
                exit(EXIT_FAILURE);
            }

            for (i = 0; i < slots; i++)
                used[i] = 0;

            for (item = list; item != NULL; item = item->next)
                ++used[item->hash % slots];

            n = used[0];
            for (i = 1; i < slots; i++)
                if (used[i] > n)
                    n = used[i];

            if (n <= 1) {
                free(used);
                return slots;
            }

            slots++;
        }
    }


    size_t generate_type(const char *type, struct type_member_list *list, const size_t size)
    {
        /* Maximum size for current hash table. */
        const size_t  max_slots = 4*size + 1;
        size_t        slots = size;
        size_t       *used, i, n;

        struct type_member_list *item;

        if (size < 1)
            return 0;

        used = malloc(max_slots * sizeof used[0]);
        if (!used) {
            fprintf(stderr, "Error: Out of memory.\n");
            exit(EXIT_FAILURE);
        }

        while (1) {

            if (slots >= max_slots) {
                fprintf(stderr, "Error: Weak hash function; hash table grows too large.\n");
                fprintf(stderr, "       (Need more than %zu slots for %zu data entries.)\n", max_slots, size);
                exit(EXIT_FAILURE);
            }

            /* Clear slot use counts. */
            for (i = 0; i < slots; i++)
                used[i] = 0;

            /* Count slot occupancies. */
            for (item = list; item != NULL; item = item->next)
                ++used[item->hash % slots];

            /* Find the maximum slot occupancy. */
            n = used[0];
            for (i = 1; i < slots; i++)
                if (used[i] > n)
                    n = used[i];

            /* Suitable size? */
            if (n <= 1)
                break;

            /* Try a larger hash table, then. */
            slots++;
        }

        free(used);

        /* Print out the contents of this hash table. */
        printf("static const struct member  struct_%s_members[%zu] = {\n", type, slots);
        for (i = 0; i < slots; i++) {
            for (item = list; item != NULL; item = item->next)
                if (item->hash % slots == i)
                    break;
            if (item) {
                printf("    { .offset  = %zu,\n", item->offset);
                printf("      .hash    = %zu,\n", item->hash);
                printf("      .namelen = %zu,\n", item->namelen);
                printf("      .name    = \"%s\" },\n", item->name);
            } else {
                printf("    { .offset  = 0,\n");
                printf("      .hash    = 0,\n");
                printf("      .namelen = 0,\n");
                printf("      .name    = NULL },\n");
            }
        }
        printf("};\n\n");

        return slots;
    }

    int main(void)
    {
        struct type_list *list;
        size_t            main_slots, i;

        add_types_and_members();

        printf("#include <stdlib.h>\n");
        printf("#include <string.h>\n");
        printf("#include <errno.h>\n");
        printf("\n");
        printf("struct member {\n");
        printf("    const size_t      offset;\n");
        printf("    const size_t      hash;\n");
        printf("    const size_t      namelen;\n");
        printf("    const char *const name;\n");
        printf("};\n");
        printf("\n");
        printf("struct type {\n");
        printf("    const size_t               hash;\n");
        printf("    const size_t               namelen;\n");
        printf("    const size_t               members;\n");
        printf("    const struct member *const member;\n");
        printf("    const char *const          name;\n");
        printf("};\n");
        printf("\n");
        printf("%s\n", hash_of_def);
        printf("\n");

        for (list = types; list != NULL; list = list->next)
            list->slots = generate_type(list->type, list->members, type_member_list_size(list->members));

        main_slots = type_slots(types);

        printf("static const size_t       num_types = %zu;\n", main_slots);
        printf("static const struct type  types[%zu] = {\n", main_slots);
        for (i = 0; i < main_slots; i++) {
            for (list = types; list != NULL; list = list->next)
                if (list->hash % main_slots == i)
                    break;

            if (list) {
                printf("    { .hash    = %zuUL,\n", list->hash);
                printf("      .namelen = %zu,\n", list->typelen);
                printf("      .members = %zu,\n", list->slots);
                printf("      .member  = struct_%s_members,\n", list->type);
                printf("      .name    = \"%s\" },\n", list->type);
            } else {
                printf("    { .hash    = 0,\n");
                printf("      .namelen = 0,\n");
                printf("      .members = 0,\n");
                printf("      .member  = NULL,\n");
                printf("      .name    = NULL },\n");
            }
        }
        printf("};\n");
        printf("\n");
        printf("size_t member_offset(const char *type, const char *name, const size_t not_found)\n");
        printf("{\n");
        printf("    const size_t  typelen = (type) ? strlen(type) : 0;\n");
        printf("    const size_t  namelen = (name) ? strlen(name) : 0;\n");
        printf("\n");
        printf("    if (typelen > 0 && namelen > 0) {\n");
        printf("        const size_t  typehash = hash_of(type, typelen);\n");
        printf("        const size_t  t = typehash %% num_types;\n");
        printf("        if (types[t].hash == typehash &&\n");
        printf("            types[t].namelen == typelen &&\n");
        printf("            !strcmp(types[t].name, type)) {\n");
        printf("            const size_t         namehash = hash_of(name, namelen);\n");
        printf("            const struct member *const member = types[t].member + (namehash %% types[t].members);\n");
        printf("            if (member->hash == namehash &&\n");
        printf("                member->namelen == namelen &&\n");
        printf("                !strcmp(member->name, name)) {\n");
        printf("                errno = 0;\n");
        printf("                return member->offset;\n");
        printf("            }\n");
        printf("        }\n");
        printf("    }\n");
        printf("    errno = ENOENT;\n");
        printf("    return not_found;\n");
        printf("}\n\n");

        return EXIT_SUCCESS;
    }
END
正如您可能已经注意到的,编写一个生成C代码的C程序是。。复杂的;写一个脚本生成一个C程序生成C代码是。。通常不值得进行维护工作。然而,这是绝对可行的,尽管维护脚本需要付出的努力比生成的代码的价值要大的风险很高。要意识到这种风险

Makefile
(运行
make
时)中的默认操作与
makeclean示例
相同。如果您将以上所有内容保存到各自的文件中,然后运行

make
你应该看到类似的东西

rm -f *.o example member-offset.c member-offset-generator.c member-offset-generator
rm -f member-offset.c member-offset-generator member-offset-generator.c
./member-offset-generator.bash mytypes.h:type1 mytypes.h:type2 > member-offset-generator.c
gcc -Wall -O2 member-offset-generator.c  -o member-offset-generator
./member-offset-generator > member-offset.c
rm -f member-offset-generator member-offset-generator.c
gcc -Wall -O2 -c member-offset.c
gcc member-offset.o main.c  -o example
因为
make
输出它运行的命令,而我没有隐藏任何命令(在相应的命令前面加上
@

那么,如果你跑

./example type1 one  type1 two  type1 three  type1 callback
示例程序应该输出

struct type1 has member one at offset 0.
struct type1 has member two at offset 1.
struct type1 has member three at offset 3.
struct type1 has member callback at offset 7.
在x86-64上,它是一个LP64体系结构(
int
为32位,而
long
和指针为64位),运行

输出

struct type2 has member four at offset 0.
struct type2 has member five at offset 1.
struct type2 has member six at offset 16.
struct type2 has member seven at offset 20.
struct type2 has member four at offset 0.
struct type2 has member five at offset 1.
struct type2 has member six at offset 12.
struct type2 has member seven at offset 16.
在x86-64上,可以使用
-m32
GCC选项编译32位代码。那么,跑步

make CFLAGS="-Wall -O2 -m32" clean all
然后

输出

struct type2 has member four at offset 0.
struct type2 has member five at offset 1.
struct type2 has member six at offset 16.
struct type2 has member seven at offset 20.
struct type2 has member four at offset 0.
struct type2 has member five at offset 1.
struct type2 has member six at offset 12.
struct type2 has member seven at offset 16.
如果我们在哈希表条目中添加对结构成员类型的支持,则可以对其进行扩展以允许某种内省

然而,我不能强调足够重要的是要考虑维持这项工作所需的维护努力。如果代码库有一套严格的编码标准,并且有人对这个代码生成器非常熟悉,能够定期检查它是否正确解析了结构,并且不止一个开发人员可以长期维护它,那么肯定;我不明白为什么不用这样的东西。否则,它可能会成为一个沉重的负担,这可能会拖垮项目的其余部分。特别是如果只有一个deve