【问题标题】:How to resolve "conflicting types error" in C?如何解决 C 中的“冲突类型错误”?
【发布时间】:2019-05-01 13:29:31
【问题描述】:

对于以下 C 代码(用于交换两个数字),我收到 swap 函数的“冲突类型”错误:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a,b;
    printf("enter the numbers to be swapped");
    scanf("%d%d",&a,&b);
    printf("before swap");
    printf("a=%d,b=%d",a,b);
    swap(&a,&b,sizeof(int));
    printf("after swap");
    printf("a=%d,b=%d",a,b);
    getch();   
}
void swap(void *p1,void *p2,int size)
{
     char buffer[size];
     memcpy(buffer,p1,size);
     memcpy(p1,p2,size);
     memcpy(p2,buffer,size);
     return(0);
}

编译器诊断:

<source>:10:6: warning: implicit declaration of function 'swap' [-Wimplicit-function-declaration]
  swap(&a,&b,sizeof(int));

  ^~~~
program:15:6: warning: conflicting types for 'swap'
 void swap(void *p1,void *p2,int size)
     ^~~~

谁能说出为什么会出现这个错误?

解决办法是什么?

【问题讨论】:

    标签: c


    【解决方案1】:

    问题是swap 在使用之前没有声明。因此,它被分配了一个“默认签名”,在这种情况下,它与它的实际签名不匹配。引用Andrey T

    参数通过集合传递 严格定义的转换。 int * 指针将作为int * 传递 例如指针。换句话说, 参数类型是暂时的 从参数类型“推导出”。仅有的 返回类型假定为int

    除此之外,您的代码还会产生许多其他警告。如果使用gcc,请使用-Wall -pedantic(甚至使用-Wextra)进行编译,并确保在继续编写附加功能之前修复每个警告。此外,您可能想告诉编译器您是在编写 ANSI C (-ansi) 还是 C99 (-std=c99)。

    一些备注:

    • 在逗号后加空格。
    • 使main 返回int
      • 并将其设为return 0return EXIT_SUCCESS
    • 导入getch的定义:#include &lt;curses.h&gt;
    • 导入memcpy的定义:#include &lt;string.h&gt;
    • 不要在 void 函数中返回任何内容。
    • 您可能希望使用malloc 分配可变大小的缓冲区。这也适用于较旧的编译器:

      void swap(void *p1, void *p2, int size) {
          void *buffer = malloc(size);
          memcpy(buffer, p1, size);
          memcpy(p1, p2, size);
          memcpy(p2, buffer, size);
          free(buffer);
      }
      

    【讨论】:

    • @AndreyT:感谢您的说明。显然,我对发生的事情的看法与现实不符。我在答案中加入了您的评论。
    • 不要使用来自&lt;curses.h&gt; 的'getch()',除非你也准备好初始化库(或者在你不准备的时候忍受核心转储)。
    【解决方案2】:

    您需要在使用前声明交换。例如,将swap 放在main 上方,或者为swap 添加一个原型,如下所示:

    void swap(void *,void *,int);
    int main () 
    

    顺便说一句,main 应该是 int 而不是 void,并且通常它返回零值,除非出现错误。

    【讨论】:

      【解决方案3】:

      首先,实际的错误消息不会造成伤害。

      其次,将缓冲区设置为 [size] 仅适用于某些编译器(这是一项新功能,并非所有编译器都具有它)。你确定是你的吗?

      第三,你需要在调用swap之前声明它。在文件顶部添加一个原型:

      void swap(void *p1,void *p2,int size);
      

      【讨论】:

        【解决方案4】:

        您未能明确声明您的swap,迫使编译器在调用时对函数做出假设。编译器根据 C 规则,将假定 swap

        int swap(int *, int *, size_t)
        

        稍后您将交换声明为

        void swap(void *, void *, int)
        

        这显然与编译器假设的不同。这就是编译器告诉你的冲突。

        另外,您的void swap 尝试return 0。你想达到什么目的?

        附:这是int main,而不是void main

        附言如果程序的输出不以换行符结尾,则程序不能保证产生任何输出。

        【讨论】:

          【解决方案5】:

          您可能想知道为什么程序在没有 swap() 原型的情况下完全可以编译,那是因为编译器不仅仅是 C99 工具。它还编译 C89 和 K&R C 程序。

          C89 添加了原型。在 C89 之前,编译器不需要查看函数的声明(原型),除非它返回 int 以外的内容,并且编译器根本不知道形式参数的类型。编译器只是使用实际参数的类型调用每个函数,它接收一组默认参数提升以简化事情。程序员将运行lint 实用程序来交叉检查实际参数和形式参数。该程序仍随 BSD 发行版一起提供。

          K&R 程序及其相应的代码样式仍然被您的编译器接受,因此当它看到没有可用原型的函数时,它会继续调用它。

          在这种情况下,您可以在调用和函数定义之间切换范例。 K&R C 假设编译器在必须生成调用时对未声明的函数做出的假设结果是无效的。即使你用 K&R 风格编写了整个程序,编译器在发现函数参数的 real 类型时也会产生同样的抱怨。

          【讨论】:

            【解决方案6】:

            对于 GCC,这是一个警告,
            当您在使用之前未声明函数时,编译器会尝试使用对该函数的调用类型来猜测声明。因此行为。

            【讨论】:

              【解决方案7】:

              好吧,它在http://codepad.org 上编译(在删除getch() 之后,这是无关紧要的)。也许您的编译器抱怨在非受限指针上使用 memcpy?

              swap() p1p2 不保证不是别名。这是一个等待发生的实际错误 - 在 &amp;a[i]&amp;a[j] 上调用交换可能会在 i==j 时炸毁 memcpy。要么使用memmove(保证不会在重叠区域爆炸),要么声明指针restricted

              【讨论】:

              • swap 的缺失声明可以编译,因为在形式上它不是 C 中的错误。它是 UB。但是我不清楚你是如何在void 函数中编译return 0 的。
              • @AnT 与你 10 年前的观点争论,正式地它是 C 语言中的一个错误...... ;)
              猜你喜欢
              • 2021-12-21
              • 2019-09-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-03-10
              • 2013-04-24
              相关资源
              最近更新 更多