取消引用指向 void 数组的指针

发布于 2024-11-28 05:44:21 字数 1568 浏览 1 评论 0原文

我正在尝试更多地了解 C 及其神秘的隐藏功能,并且我尝试制作一个包含指向 void 的指针的示例结构,旨在用作数组。 编辑:重要提示:这是针对原始 C 代码的。

假设我有这个结构。

    typedef struct mystruct {
        unsigned char foo;
        unsigned int max;
        enum data_t type;
        void* data;

    } mystruct;

我希望数据能够容纳无符号字符、无符号短整型和无符号长整型的 max 个,data_t 枚举包含 这 3 种情况的值。

    enum Grid_t {gi8, gi16, gi32}; //For 8, 16 and 32 bit uints.

然后我有一个函数来初始化和分配这个结构之一,并且应该返回一个指向新结构的指针。

    mystruct* new(unsigned char foo, unsigned int bar, long value) {
        mystruct* new;
        new = malloc(sizeof(mystruct)); //Allocate space for the struct.
        assert(new != NULL);
        new->foo = foo;
        new->max = bar;
        int i;
        switch(type){
            case gi8: default:
                new->data = (unsigned char *)calloc(new->max, sizeof(unsigned char));
                assert(new->data != NULL);
                for(i = 0; i < new->max; i++){
                    *((unsigned char*)new->data + i) = (unsigned char)value;
                    //Can I do anything with the format new->data[n]? I can't seem
                    //to use the [] shortcut to point to members in this case!
                }
            break;
        }
        return new;
    }

编译器没有返回警告,但我不太确定这个方法。这是使用指针的合法方式吗?

有更好的方法©吗?

我错过了打电话给它。像 mystruct* P; P = 新(0,50,1024);

工会很有趣,但不是我想要的。因为无论如何我都必须单独处理每个具体案例,所以选角似乎和联合一样好。我特别希望拥有比 32 位数组大得多的 8 位数组,因此联合似乎没有帮助。为此,我将其设置为一个长整型数组:P

I am attempting to learn more about C and its arcane hidden powers, and I attempted to make a sample struct containing a pointer to a void, intended to use as array.
EDIT: Important note: This is for raw C code.

Let's say I have this struct.

    typedef struct mystruct {
        unsigned char foo;
        unsigned int max;
        enum data_t type;
        void* data;

    } mystruct;

I want data to hold max of either unsigned chars, unsigned short ints, and unsigned long ints, the data_t enum contains
values for those 3 cases.

    enum Grid_t {gi8, gi16, gi32}; //For 8, 16 and 32 bit uints.

Then I have this function that initializes and allocates one of this structs, and is supposed to return a pointer to the new struct.

    mystruct* new(unsigned char foo, unsigned int bar, long value) {
        mystruct* new;
        new = malloc(sizeof(mystruct)); //Allocate space for the struct.
        assert(new != NULL);
        new->foo = foo;
        new->max = bar;
        int i;
        switch(type){
            case gi8: default:
                new->data = (unsigned char *)calloc(new->max, sizeof(unsigned char));
                assert(new->data != NULL);
                for(i = 0; i < new->max; i++){
                    *((unsigned char*)new->data + i) = (unsigned char)value;
                    //Can I do anything with the format new->data[n]? I can't seem
                    //to use the [] shortcut to point to members in this case!
                }
            break;
        }
        return new;
    }

The compiler returns no warnings, but I am not too sure about this method. Is it a legitimate way to use pointers?

Is there a better way©?

I missed calling it. like mystruct* P; P = new(0,50,1024);

Unions are interesting but not what I wanted. Since I will have to approach every specific case individually anyway, casting seems as good as an union. I specifically wanted to have much larger 8-bit arrays than 32-bits arrays, so an union doesn't seem to help. For that I'd make it just an array of longs :P

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冰火雁神 2024-12-05 05:44:21

不,您不能取消引用 void* 指针,这是 C 语言标准所禁止的。在此之前,您必须将其转换为具体的指针类型。

作为一种替代方案,根据您的需要,您还可以在结构中使用 union 而不是 void*

typedef struct mystruct {
    unsigned char foo;
    unsigned int max;
    enum data_t type;
    union {
        unsigned char *uc;
        unsigned short *us;
        unsigned int *ui;
    } data;
} mystruct;

在任何给定时间,只有 data 之一.ucdata.usdata.ui 是有效的,因为它们都在内存中占用相同的空间。然后,您可以使用适当的成员来获取数据数组,而无需从 void* 进行转换。

No, you cannot dereference a void* pointer, it is forbidden by the C language standard. You have to cast it to a concrete pointer type before doing so.

As an alternative, depending on your needs, you can also use a union in your structure instead of a void*:

typedef struct mystruct {
    unsigned char foo;
    unsigned int max;
    enum data_t type;
    union {
        unsigned char *uc;
        unsigned short *us;
        unsigned int *ui;
    } data;
} mystruct;

At any given time, only one of data.uc, data.us, or data.ui is valid, as they all occupy the same space in memory. Then, you can use the appropriate member to get at your data array without having to cast from void*.

云之铃。 2024-12-05 05:44:21

这样一来

typedef struct mystruct 
{
    unsigned char foo;
    unsigned int max;
    enum data_t type;
    union
    {
        unsigned char *chars;
        unsigned short *shortints;
        unsigned long *longints; 
    };
} mystruct;

,根本就不需要施展了。只需使用 data_t 来确定您要访问哪个指针。

What about

typedef struct mystruct 
{
    unsigned char foo;
    unsigned int max;
    enum data_t type;
    union
    {
        unsigned char *chars;
        unsigned short *shortints;
        unsigned long *longints; 
    };
} mystruct;

That way, there is no need to cast at all. Just use data_t to determine which of the pointers you want to access.

青衫儰鉨ミ守葔 2024-12-05 05:44:21

type 应该是函数的参数吗? (不要命名这个函数或任何变量 new ,否则任何试图使用它的 C++ 程序员都会追捕你)

如果你想使用数组索引,你可以使用一个临时指针,如下所示

unsigned char *cdata = (unsigned char *)new->data;
cdata[i] = value;

:真的不认为你的方法有问题。如果您期望特定的大小(我认为您确实给出了名称 gi8 等),我建议包括 stdint.h 并使用 typedefs uint8_t、uint16_tuint32_t

Is type supposed to be an argument to the function? (Don't name this function or any variable new or any C++ programmer who tries to use it will hunt you down)

If you want to use array indices, you can use a temporary pointer like this:

unsigned char *cdata = (unsigned char *)new->data;
cdata[i] = value;

I don't really see a problem with your approach. If you expect a particular size (which I think you do given the name gi8 etc.) I would suggest including stdint.h and using the typedefs uint8_t, uint16_t, and uint32_t.

世俗缘 2024-12-05 05:44:21

指针只是内存空间中的一个地址。您可以选择按照您的意愿解释它。查看union以获取有关如何以多种方式解释同一内存位置的更多信息。

指针类型之间的转换在 C 和 C++ 中很常见,并且使用 void* 意味着您不希望用户意外取消引用(取消引用 void* 将导致错误,但在转换为 int* 时取消引用同一指针则不会)

A pointer is merely an address in the memory space. You can choose to interpret it however you wish. Review union for more information on how you can interpret the same memory location in multiple ways.

casting between pointer types is common in C and C++, and the use of void* implies that you dont want users to accidentally dereference (dereferencing a void* will cause an error, but dereferencing the same pointer when cast to int* will not)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文