【问题标题】:Can I name a variable with the same name as a typedef'd structure name?我可以命名一个与 typedef 结构名称同名的变量吗?
【发布时间】:2012-11-02 16:39:03
【问题描述】:

这是结构声明代码。

struct list_el {
    int val;
    struct list_el * next;
};

typedef struct list_el item;

当我编写这样的函数时,编译器会出错。它说cur undeclared before first use

bool delete(item* item)
{
    assert(item != NULL);

    item* cur = NULL;
    cur = head;
    item* prev = NULL;
    while (cur) {
        if (cur == item) {
            if (prev == NULL) {
                head = item->next;
            } else {
                prev->next = item->next;
            }
            free(item);
            return true;
        }

        prev = cur;
        cur = cur->next;
    }
    return false;
}

在我查阅参考资料后,它说typedef 工作只是有点像#define。它只是在编译时进行替换。这就是代码无法编译的原因吗?

【问题讨论】:

  • typedef 不像#define 那样工作。哪个参考文献这么说的?

标签: c gcc


【解决方案1】:

在这段代码中:

bool delete(item* item)
{
    item *cur = NULL;

第三行中的item 被视为变量item(函数的参数)的名称,而不是类型。因此,第三行看起来好像是一个将item 乘以未定义变量cur 的表达式,这会导致问题;表达式的其余部分也是假的。

如果这不是您想要的,请不要为类型和变量使用相同的名称。即使您不混淆自己和编译器,也会混淆其他人。


无论哪个参考来源说typedef#define '相同'都应该从你的参考列表中删除现在!如果它不能区分两种根本不同的结构,那是很危险的,因为你不知道它何时会误导你(但这是一种误导你的情况)。

【讨论】:

  • 非常感谢您的回答。
  • @Jonathan Leffler (item* item) 会产生编译错误吗?
  • @GrijeshChauhan:在 GCC 下不会导致编译错误。我有点惊讶。我认为这取决于范围。函数定义有一个新作用域,在该作用域中,普通名称 item 现在表示变量。我不确定这就是你勉强糊口的方式,但它看起来是半可信的。你可以看到它:int x = 0; int func(void) { int y = x; int x = y + 1; ... } 这是合法的。函数中第一个x是全局变量;第二个是一个新的局部变量,它会影响全局。我假设问题中的函数情况类似。
  • 你是对的,我自己也检查过,是的,由于范围......它在 C 中也是正确的,但在 Java 中不是。 : 谢谢
  • 你改变了答案!...你写了一些关于 c99 和 c89 的文章
【解决方案2】:

typedef 只是现有类型的新名称。定义由预处理器处理,而 typedef 由 C 编译器本身处理。 [复制自此link]

检查这个问题:Are typedef and #define the same in c?

【讨论】:

  • 此外,强制编译器从上下文中猜测您是否引用了对象的实例,或者类型名称至少是一种可悲的方法,编译器不应允许。一个有点疯狂的例子 typedef int b;双乙; b = 4; - 编译错误
【解决方案3】:

typedef#define不完全相同

以下是示例的区别:

#define cptr1 char*

typedef char* cptr2;

在代码中:

           int main()
            {
             cptr1 c1,c2; // first case : 
        // here c1 will be pointer to char but c2 is only char as cptr 
   // is directly replaced by char* by preprocessor
            cptr2 c3,c4; // second case :
      // here c3 and c4 both are pointers to char 
            }

【讨论】:

    【解决方案4】:

    您应该在编译代码时使用-Wshadow。 然后,gcc 会告诉你哪里错了。 :-) 如下:
    declaration of ‘item’ shadows a global declaration [-Wshadow]

    【讨论】:

    • 既然我是c编程的新手,那么我应该在gcc中打开尽可能多的警告选项吗?
    • @user674199,我想是的。如果你打开它们,你会避免很多错误。它们将节省您的调试时间。 :-)
    • 如果您使用 GCC 进行编译,那么使用 -Wall 可以避免很多问题。我也使用了一些额外的选项——有时,但并非总是如此,包括-Wshadow。由于我使用的逆行代码和过时代码,我发现-Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition 很有用。我尽可能用-Wextra 编译,但这是一个苛刻的编码标准;我会原谅-Wextra 下的一些警告(但其他选项下的警告很少)。使用 -Werror 也能让你诚实。
    【解决方案5】:

    Jonathan Leffler 回答了你的问题。

    我只是想补充一下:如果你用c++编写代码,你不需要typedef,所以你可以像这样实现你的列表:

    struct list_el {
        int val;
        list_el *next;
    };
    
    bool delete_element(list_el *item)
    {
        list_el *cur = NULL;
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-13
      • 2017-10-20
      • 1970-01-01
      相关资源
      最近更新 更多