在C语言中,一个函数是否必须有返回语句?

3
PUBLIC void delset( set )
SET *set;
{
    /* Delete a set created with a previous newset() call. */

    if( set->map != set->defmap )
        free( set->map );
    free( set );

}

在C函数中是否一定需要有一个返回语句?上面的函数会抛出如下警告。请注意,我没有返回语句。

src/tools/set.c: In function ‘delset’:
src/tools/set.c:41:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

一旦添加了return 0;,警告就会消失。 即使我只指定return;也会显示警告。

PUBLIC void delset( set )
SET *set;
{
    /* Delete a set created with a previous newset() call. */

    if( set->map != set->defmap )
        free( set->map );
    free( set );

    return 0;
}

我正在使用 gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4编辑 看起来只是一个标记。这个SO问题似乎比我更好地解释了它的含义。
void delset( set )
SET *set;
{
    /* Delete a set created with a previous newset() call. */

    if( set->map != set->defmap )
        free( set->map );
    free( set );        
}

我将函数前面的PUBLIC标记和底部的返回行删除,但仍然出现相同的错误。

typedef struct _set_
{
    unsigned char nwords;                                   /* Number of words in map */
    unsigned char compl;                                    /* is a negative true set if true */
    unsigned nbits;                                         /* Number of bits in map */
    _SETTYPE *map;                                          /* Pointer to the map */
    _SETTYPE defmap[ _DEFWORDS ];                           /* The map itself */

} SET;

以下头文件(debug.h)的包含导致了问题。不确定具体是哪一行导致的。
#ifdef DEBUG
#   define PRIVATE
#   define D (x) x
#else
#   define PRIVATE static
#   define D (x)
#endif
#   define PUBLIC

#ifdef MSDOS
#   define MS(x) x 
#   define UX(x)
#   define ANSI
#   define _8086
#else
#   define MS(x)
#   define UX(x) x
#   define O_BINARY 0 /*no binary input mode in UNIX open() */
    typedef long time_t; /* for the VAX, may have to change this */
    typedef unsigned s1ze_t; /* for the VAX, may have to change this. Renamed the type as s1ze_t as stdio.h contains a type of the same name */
    extern char *strdup(); /* You need to supply one. */
#endif

#ifdef ANSI /* If ANSI is defined, put arg lists into */
#   define P(x) x /* function prototypes. */
#   define VA_LIST ... /* and use ellipsis if a variable number of args */
#else
#   define P(x) () /*Otherwise, discard argument lists and translate*/
#   define void char /* void keyword to int. */
#   define VA LIST _a_r_g_s /* don't use ellipsis */
#endif

/* SEG (p) Evaluates to the segment portion of an 8086 address.
 * OFF (p) Evaluates to the offset portion of an 8086 address.
 * PHYS (p) Evaluates to a long holding a physical address
 */

#ifdef _8086
#   define SEG(p) ( ((unsigned *)&(p)) [1] )
#   define OFF(p) ( ((unsigned *)&(p)) [0] )
#   define PHYS(p) (((unsigned long)OFF(p)) + ((unsigned long)SEG(p) << 4))
#else
#   define PHYS(p) (p)
#endif

/* NUMELE (array) Evaluates to the array size in elements
 * LASTELE(array) Evaluates to a pointer to the last element
 * INBOUNDS(array,p) Evaluates to true i f p points into the array.
 * RANGE(a,b,c) Evaluates to true i f a <= b <= c
 * max(a,b) Evaluates to a or b, whichever is larger
 * min (a, b) Evaluates to a or b, whichever is smaller
 *
 * NBITS (type) Returns number of bits in a variable of the indicated
 * type;
 * MAXINT Evaluates to the value of the largest signed integer
 */

#define NUMELE(a)       (sizeof(a)/sizeof(*(a)))
#define LASTELE(a)      ((a) + (NUMELE(a)-1))
#define TOOHIGH(a,p)        ((p) - (a) > (NUMELE(a) - 1))
#define TOOLOW(a,p)         ( (p) - (a) < 0 )
#define INBOUNDS(a,p)       (!(TOOHIGH(a,p) || TOOLOW(a,p))

#define _IS(t, x) (((t)1 << (x)) != 0) /* Evaluate true if the width of a */
                    /* variable of type of t is < x. The !=0 */
                    /* assures that the answer is 1 or 0 */

#define NBITS(t) (4 * (1 + _IS(t, 4) + _IS(t, 8) + _IS(t,12) + _IS(t, 16) + _IS(t,20) + _IS(t,24) + _IS(t,28) + _IS(t,32) ) 


#define MAXINT (((unsigned)~0) >> 1)

#ifndef max
#   define max(a, b)    (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#   define min(a,b)     (((a) < (b)) ? (a) : (b))
#endif
#define RANGE(a,b,c)    ((a) <= (b) && (b) <= (c))

12
PUBLIC 是什么?公共的。在计算机编程中,PUBLIC 是一种关键字,用于表示可从程序的任何部分访问的变量、函数或类成员。 - alk
2
对于非void函数来说这是必要的。如果你不想让函数返回一个值,就声明它为void。这样控制流可以到达函数的结尾而不会出错(你也可以使用裸的return语句)。如果函数是非void的,那么它应该总是返回一个值。 - Tom Karzes
6
另外,为什么你不使用普通的函数原型?在史前时期声明参数列表之后的参数已经被淘汰了。现在没有人再这样做了。 - Tom Karzes
2
请发布一个 MCVE。您发布了一个空函数,但编译器消息却指向一个非空函数。 - M.M
3
你的问题在这里:# define void char /* void关键字变成了int。*/。我会将其翻译为“将void关键字定义为char类型,/表示注释内容/”。请注意,该定义可能会导致代码出现问题,因为它违反了C语言规范。 - Abhineet
显示剩余15条评论
3个回答

5

返回语句并非必需。

如果您的函数具有非 void 返回类型,并且您没有返回任何值,并且调用者使用了返回值,则会导致未定义的行为。

编译器发出警告,因为您的函数具有非 void 返回类型,它认为您可能想返回一个值,但是却忘记了。

您发布的代码与编译器消息不相对应,除非 PUBLIC 被定义为某些奇怪的东西。


我敢打赌,有一种方法可以针对一个特定的函数禁用警告,而不是全局禁用。这样编译器就会在其他位置向我显示警告。就像Java中的 @SuppressWarnings 一样。 - ShaggyInjun
@ShaggyInjun 修复错误比抑制警告更好。 - M.M
不确定警告是否来自 PUBLIC。在我删除它和返回语句之后,警告仍然存在。 - ShaggyInjun

0

如果函数的返回类型不是void,则您将始终收到警告。

如果您想停止执行无返回值的函数(即使可能还有指令要执行),请使用return;

希望我能帮到您!


0

我觉得你可能对一些基本语法有误解,但如果你在函数名(SET)前面插入“void”,编译器就会理解这个函数不返回任何值,警告也会消失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接