Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当超级结构引用非常量时,如何使用常量C结构?_C_Struct_Constants_Qualifiers - Fatal编程技术网

当超级结构引用非常量时,如何使用常量C结构?

当超级结构引用非常量时,如何使用常量C结构?,c,struct,constants,qualifiers,C,Struct,Constants,Qualifiers,考虑以下示例: typedef struct Collection { ... } Collection; typedef struct Iterator { Collection* collection; } Iterator; 迭代器提供集合修改函数,因此它保存非常量集合的地址。但是,它还提供了非修改函数,这些函数与常量集合一起使用是完全合法的 void InitIterator(Iterator* iter, Collection* coll) { iter-&

考虑以下示例:

typedef struct Collection
{
    ...
} Collection;

typedef struct Iterator
{
    Collection* collection;
} Iterator;
迭代器提供集合修改函数,因此它保存非常量集合的地址。但是,它还提供了非修改函数,这些函数与常量集合一起使用是完全合法的

void InitIterator(Iterator* iter, Collection* coll)
{
    iter->collection = coll;
}

void SomeFunction(const Collection* coll)
{
    // we want to use just non-modifying functions here, as the Collection is const
    Iterator iter;
    InitIterator(&iter, coll); // warning, call removes const qualifier
}
我正在C中寻找解决方案。 我确实看到了一些选择:

1。在初始化时,将集合强制转换为非常量。 这可能不是未定义的行为,因为对象最终不应该被修改。但这令人毛骨悚然,因为有一个常量对象,这样做是自找麻烦。迭代器将成为处理集合的一种广泛使用的通用机制。在修改常量集合时没有编译器警告是非常糟糕的

2.两种迭代器类型,一种是只读版本,具有const Collection*成员。 这会使使用变得复杂,可能需要重复某些功能,可能由于转换步骤而降低效率。我真的不想让API复杂化,让它有两个不同的结构和两组函数

3.同时具有两个指针的迭代器,Init使用两个集合指针

typedef struct Iterator
{
    const Collection* collectionReadable; // use this when reading
    Collection* collectionWritable;       // use this when writing
} Iterator;
当有一个常量集合时,非常量参数必须变为NULL,并且最终尝试修改集合将崩溃(尝试取消引用NULL指针),这是好的(安全的)。我们有额外的存储成本。拿同一个集合的两个指针是很尴尬的

void InitIterator(Iterator* iter, Collection* coll)
{
    iter->collection = coll;
}

void SomeFunction(const Collection* coll)
{
    // we want to use just non-modifying functions here, as the Collection is const
    Iterator iter;
    InitIterator(&iter, coll); // warning, call removes const qualifier
}
我也有点担心编译器在同一上下文中看到两个指针,这意味着如果集合通过可写指针进行修改,编译器必须意识到只读指针可能指向同一个对象,并且需要重新加载它,尽管有const限定符。这安全吗

你会选哪一个?为什么?
你知道解决这个问题的更好方法吗?

是的,有两个指针指向同一个对象是安全的,一个是常量,另一个是非常量。const仅仅意味着不能通过这个特定的指针修改对象,但是如果存在这样的指针,可以通过其他指针修改对象。然而,尽管它是安全的,但这并不一定意味着您应该选择具有两个指针的解决方案

typedef struct Iterator
{
    const Collection* collectionReadable; // use this when reading
    Collection* collectionWritable;       // use this when writing
} Iterator;
有关完全正确工作的代码示例,请参见:

int x = 5;
const int *p = &x;
printf("%d\n", *p);
x = 7;
printf("%d\n", *p);
现在,即使p是常量指针,*p也会发生变化

这里的目标是避免代码重复,因此只需将常量指针转换为非常量指针。只要不修改对象,它是安全的。在C标准库中有很多类似的例子。例如,strchr()将一个const char指针放入字符串中,然后返回一个char指针,以防字符串不是const,并且您希望通过返回值对其进行修改。我会选择C标准库中采用的解决方案,即类型转换


您已经注意到C中的常量限定符并不完美。遇到这样的问题时,有很多用例,最简单的方法通常是接受它并不完美并进行类型转换。

为什么某些函数必须使用指向常量的指针?只要让用户传递一个非常量对象。@reader函数“保证”不会修改对象的情况不计其数。它有利于优化,并且在多线程代码中是无价的。我不确定类型转换是最好的解决方案,因为迭代器将成为外部广泛使用的对象的具体细节。我认为要求所有的用户打破他们的常数是不好的。否则我同意你的看法——如果只在内部使用,在我可以控制使用的情况下,打字可能是最好的。你的回答实际上让我更倾向于第三种选择,但我还没有决定。