将指向属于同一类型结构的成员的结构的指针分配给指向同一类型结构的另一个指针

将指向属于同一类型结构的成员的结构的指针分配给指向同一类型结构的另一个指针

问题描述:

即使对我来说,这个问题听起来也超级令人困惑,它可能看起来很明显或已经回答了,但我搜索了很多东西,虽然我发现了有趣的东西,但我没有找到完全适合我的问题的答案.下面是一些 C 代码,可以更好地说明我的怀疑:

This question sounds super confusing even for me, and it may seem obvious or already answered, but I have searched a lot and although I found interesting things, I didn't find an answer exactly for my question. Here is some C code that will show much better my doubt:

typedef struct Node_struct {
   char keyLine[100];
   int occurrences;
   struct Node* leftChild;
   struct Node* rightChild;
   struct Node* parent;
} Node;

typedef struct Tree_struct {
   Node* root;
} Tree;

int insertNode(Tree* myTree, Node* newNode) {
    ...
    Node* currentNode = myTree->root;
    ...
    if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
        currentNode = (Node*)currentNode->leftChild;
    }
    ...
 }

这个代码正确吗?由于 currentNodeNode* 类型,而 currentNode->leftChildstruct Node* 类型,我必须强制转换 (Node*)currentNode->leftChild 以便它可以分配给 currentNode.但我不确定这是否正确、是否必要,或者是否有更好的方法来做同样的事情.

Is this code correct? Since currentNode is of type Node*, and currentNode->leftChild is of type struct Node*, I had to cast (Node*)currentNode->leftChild so that it could be assigned to currentNode. But I am not sure if this is correct, necessary, or if there is a better way to do the same.

同样,我也有这个:

Node* coverNode = NULL;
...
coverNode->leftChild = (struct Node*)newNode;

应该写什么

假设问题中的代码是这样写的:

What should be written

Suppose the code in the question were written like this:

typedef struct Node {     // Not Node_struct as in the question!
   char keyLine[100];
   int occurrences;
   struct Node* leftChild;
   struct Node* rightChild;
   struct Node* parent;
} Node;

那么名称Node 将是struct Node 的同义词(别名).(对于任何 typedef XY;Y 成为 X 类型的同义词——在你的情况下,Xstruct NodeY 将是节点.)

Then the name Node would be a synonym (alias) for struct Node. (For any typedef X Y;, Y becomes a synonym for type X — where in your case, X would be struct Node and Y would be Node.)

演员阵容:

currentNode = (Node *)currentNode->leftChild;

将是不必要的(但大部分是无害的),因为它是一个空操作——类型 struct Node *Node * 将是同一个指针的两个名称类型.类似的:

would be unnecessary (but mostly harmless) because it would be a no-op — the types struct Node * and Node * would be two names for the same pointer type. Similarly for:

coverNode->leftChild = (struct Node *)newNode;

演员表是不必要的,但(大部分)是无害的.会存在将人与演员混淆的小风险.如果可能的话,最好避免强制转换,如果没有强制转换会更好地编写这些:

The cast would be unnecessary but (mostly) harmless. There would be a small risk of confusing people with the cast. It is better to avoid casts when possible, and these would be better written without the casts:

currentNode = currentNode->leftChild;
coverNode->leftChild = newNode;

写了什么

typedef struct Node_struct {
   char keyLine[100];
   int occurrences;
   struct Node* leftChild;
   struct Node* rightChild;
   struct Node* parent;
} Node;

现在我们使用了三个类型名称:struct Node_structstruct NodeNode.在这种情况下,struct Node_structNode 是同义词,而 struct Node 是一个不完整的结构类型(或者,至少,它是不完整的通过问题中的任何代码).它与 struct Node_structNode 完全无关,除非巧合的是它在结构内部被引用.

Now we have three type names in play: struct Node_struct, struct Node, and Node. In this case, struct Node_struct and Node are synonyms, and struct Node is an incomplete structure type (or, at least, it is not completed by any code in the question). It is wholly unrelated to either struct Node_struct or Node except by the coincidence that it is referenced inside the structure.

使用这种表示法,强制转换是必要的",因为您在指向不相关类型(struct Node *struct Node_struct *)的指针之间进行转换.幸运的是,有规则说所有结构类型指针都是可以相互转换的,并且必须具有相同的大小和对齐要求(C11 §6.2.5 类型¶28§6.3.2.3 指针¶7).

With this notation, the casts are 'necessary' because you're converting between pointers to unrelated types (struct Node * and struct Node_struct *). Fortunately, there are rules that say all structure type pointers are inter-convertible and must have the same size and alignment requirements (C11 §6.2.5 Types ¶28 and §6.3.2.3 Pointers ¶7).

但是您应该删除 Node_struct_struct 部分,以使本答案第一部分的规则适用.在 C 中,使用 (IMO) 是明智的:

But you should drop the _struct part of Node_struct to make the rules of the first part of this answer apply. In C, it is (IMO) sensible to use:

typedef struct SomeTag SomeTag;

以便您随后可以使用 SomeTag * 等.第一个 SomeTag 在标签名称空间中,不会与第二个 SomeTag 冲突>,它在普通标识符命名空间中.参见 C11 §6.2.3 标识符的命名空间.

so that you can subsequently use SomeTag * etc. The first SomeTag is in the tags name space and does not conflict with the second SomeTag, which is in the ordinary identifiers name space. See C11 §6.2.3 Name spaces of identifiers.

另见:

  • Which part of the C standard allows this code to compile?
  • Does the C standard consider that there are one or two struct uperms_entry types in this code?
  • C style/C++ correctness — is struct, union, enum tag same as type name bad in any way?