【问题标题】:static const char * - defined but not usedstatic const char * - 已定义但未使用
【发布时间】:2012-01-08 21:01:05
【问题描述】:

我们需要在每个头文件 (.h) 和源文件 (.cpp) 中定义一个 const static char 指针,以符合公司编码标准。

static const char * one_time_param = "ABCDEFG";

编译时,编译器会生成大量“已定义但未使用”的警告。请问有人有解决这个问题的办法吗?

-Wno-unused-parameter

使用上面的编译器标志,我们可以抑制这些警告。但是,这也抑制了一些可能需要注意的其他未使用的参数。我们尝试了这些仅适用于函数参数的解决方案。

Q_UNUSED

在 Qt 中,并且

#define UNUSED(x) ((void)(x))

上一个类似问题:

How can I hide "defined but not used" warnings in GCC?

【问题讨论】:

标签: c++ qt


【解决方案1】:

在这种情况下通常也是 const 指针, 所以尝试使用:

static const char * const one_time_param = "ABCDEFG";

【讨论】:

  • 这对我也有用。通过将指针声明为 const 你具体实现了什么?
  • 这在 gcc 2.95 上对我有用,这是古代 c 编译器的黄金标准
  • 这也对我有用,让我不必为我的 constants.h 创建源文件。真的很高兴偶然发现了这个答案。
【解决方案2】:

首先 - 公司编码标准可以说是在浪费空间。如果您要这样做,请使用数组而不是 char *,这样您就只存储数据而不是指针和数据:

static const char one_time_param[] = "ABCDEFG";

接下来,这大概是用于文件识别 - 至少,这是我使用它的目的。有几件事需要注意,从多年的经验中学到。 (我仍然喜欢在源文件中嵌入版本号——因此我还没有全心全意地转向 DVCS。)

  1. 为避免出现警告,您必须使符号在文件外可见。
  2. 反过来,这意味着您必须使变量名唯一。
  3. 我目前正在使用基于文件名的名称:jlss_id_filename_c[] 等。

    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_errno_c[] = "@(#)$Id: errno.c,v 3.3 2011/09/07 22:33:45 jleffler Exp $";
    #endif /* lint */
    
  4. AT&T SVR4 C 编译器和支持软件支持#ident 指令:

    #ident "@(#)$Id: errno.c,v 3.3 2011/09/07 22:33:45 jleffler Exp $"
    

    编译器将字符串包含在目标文件的“cmets”部分中,以及用于操作 cmets 部分的工具 (mcs)(选项 -d 删除它,-c 压缩它,IIRC) .这部分是二进制文件的一部分,但不会在运行时加载到内存中。

  5. 在 GCC 发展的某一时刻,结合我使用的命令行选项,除非我声明并定义了变量,否则我会收到警告,因此我的新源文件的“模板”会生成:

    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    extern const char jlss_id_filename_c[];
    const char jlss_id_filename_c[] = "@(#)$Id$";
    #endif /* lint */
    

    但是,这些天我通常会删除声明,并且不会收到编译器警告。

  6. 作为使用文件名作为变量名基础的替代方法,您可以生成一个十六进制的 UUID 或 GUID 名称并将其用作变量名,并带有前缀以确保第一个字符是字母。

  7. 在标头中,您不希望在包含标头的每个源文件中都定义该材料,因为 (a) 它会成为程序大小的显着(但不一定是显着)开销,并且 (b) 您不能相乘定义全局变量(您可以多次声明它们;这不是问题)。所以,我的标题有这样的节:

    #ifdef MAIN_PROGRAM
    #ifndef lint
    /* Prevent over-aggressive optimizers from eliminating ID string */
    const char jlss_id_stderr_h[] = "@(#)$Id: stderr.h,v 10.3 2011/11/28 04:49:24 jleffler Exp $";
    #endif /* lint */
    #endif
    

    然后,当我希望标题定义值时,我在相应源文件的顶部有#define MAIN_PROGRAM。例如,通过在该名称的程序上运行 what errno,我得到输出:

    errno:
    $Id: errno.c,v 3.3 2011/09/07 22:33:45 jleffler Exp $
    $Id: range.h,v 1.8 2008/02/11 07:39:36 jleffler Exp $
    $Id: stderr.h,v 10.3 2011/11/28 04:49:24 jleffler Exp $
    $Id: errhelp.c,v 8.5 2009/03/02 19:13:51 jleffler Exp $
    $Id: range2.c,v 1.8 2008/02/11 08:44:50 jleffler Exp $
    $Id: stderr.c,v 10.7 2011/11/28 04:49:24 jleffler Exp $
    stderr.c configured with USE_STDERR_FILEDESC
    stderr.c configured with USE_STDERR_SYSLOG
    

旧式

这是一个完整(并且非常有用)的程序,展示了旧式的经商方式。

/*
@(#)File:            $RCSfile: al.c,v $
@(#)Version:         $Revision: 1.4 $
@(#)Last changed:    $Date: 1996/08/13 11:14:15 $
@(#)Purpose:         List arguments one per line
@(#)Author:          J Leffler
@(#)Copyright:       (C) JLSS 1992,1996
@(#)Product:         :PRODUCT:
*/

/*TABSTOP=4*/

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

#ifndef lint
static const char sccs[] = "@(#)$Id: al.c,v 1.4 1996/08/13 11:14:15 johnl Exp $";
#endif

int main(int argc, char **argv)  
{ 
    while (*++argv) 
        puts(*argv);
    return(EXIT_SUCCESS); 
}

注意:编译时,版本字符串不包含在二进制文件(或目标文件)中。当使用在 MacOS X 10.7.2 上编译的 GCC 4.6.1 编译时,这目前不会给我任何警告:

gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \
    -Wstrict-prototypes -Wmissing-prototypes -o al al.c

当我运行what al 时,我没有得到任何识别输出。

【讨论】:

  • 究竟是哪一部分抑制了警告?我无法理解这条关键信息。
  • 使变量在外部可见(非静态)意味着编译器必须保留它,因为它可能在另一个文件中被引用。
【解决方案3】:

one_time_param.h

#ifndef ONE_TIME_PARAM_H
#define ONE_TIME_PARAM_H

extern const char* one_time_param;

#endif

one_time_param.cpp

#include "one_time_param.h"

const char* one_time_param = "ABCDEFG";

然后在每个头文件和源文件中包含 one_time_param.h。

挠头>如果你需要static,这当然行不通。

【讨论】:

    【解决方案4】:

    在项目的全局头文件中声明一个宏,如:

    #define DECLARE_ONETIME_CONST(name,value) \
        static const char* name = (value); \
        static const char nowarning_##name = name[0];
    

    然后在你的文件中说:

    DECLARE_ONETIME_CONST(one_time_param, "ABCDEFG");
    

    似乎有效。不管人们对宏和令牌粘贴有什么想法,至少使用宏,当人们意识到它们很愚蠢时,您将能够找到这些东西并摆脱它们。

    【讨论】:

      【解决方案5】:

      在单个标头中定义它,在标头内定义单个内联函数以“获取”指针的值,然后在需要定义的任何位置包含此标头。

      【讨论】:

        【解决方案6】:

        该变量是否会被某些检查可执行文件的外部实用程序引用,或者它只是您必须在源代码中拥有的东西?

        如果您只是必须在源代码中拥有它,而不必在编译后的可执行文件中,为什么不 #if 它出来:

        #if 0
        static const char * one_time_param = "ABCDEFG";
        #endif
        

        此方法的额外好处是您不再需要担心头文件中的名称冲突。

        【讨论】:

        • 感谢您的提示,但我们正在使用它来注释掉大部分内容。
        【解决方案7】:

        你总是可以绕过它。例如if (one_time_param[0] == one_time_param[0]); 最小的计算量,它应该消除警告。该行可能会被优化为无操作,因为它对程序本质上是无用的。

        这取决于您希望解决方案有多优雅。也许有人可以推荐一个可以消除警告的编译器标志。

        【讨论】:

        • 其实也不是没用。您可以使用 svn Id 标记和 ident 程序来确定程序中文件的修订版本。好吧,您也可以在那里存储一些版权或其他任何内容。这是很常见的做法。
        • 我的意思是比较没用,不是字符串本身。比较只是说“如果是真的,什么也不做。”
        • 哦,是的。但是我认为比较的问题是您必须将其置于全局范围内。可能实现,但与明确将此事物标记为“已使用”相比,代码量太大。
        • 它还会在某些编译器上引起“与自身比较”的警告。和“你真的是说';'这里”在其他人身上。
        • 很公平。我在 gcc 4.2.1 上对其进行了测试,它运行良好,但就像我在回答中所说的那样:我确信有一个更优雅的解决方案。
        【解决方案8】:

        【讨论】:

        • 文档说它只适用于函数...对吗?
        猜你喜欢
        • 1970-01-01
        • 2012-12-26
        • 1970-01-01
        • 2017-03-29
        • 1970-01-01
        • 2013-07-01
        • 1970-01-01
        • 2016-01-19
        • 2011-07-27
        相关资源
        最近更新 更多