【问题标题】:atof coredump with getoptatof 核心转储与 getopt
【发布时间】:2017-08-10 09:07:48
【问题描述】:

我正在编写一个 C++ 应用程序,它将华氏温度转换为摄氏度和开尔文,将开尔文转换为摄氏度和华氏度等。由于在这里编写交互式应用程序很愚蠢,我决定熟悉 unistd.h 中的 getopt 函数.

格式: F2C -k 273.15

输出:

FAHR CELSIUS KELVIN

32 0 273.15

这是我的代码:

#include <iostream>
#include <stdlib.h>
#include <unistd.h>

#define VERSION 0.1
#define HELP help(argv[0])

#define OPTS "vk:f:c:h"
float ver = (float)VERSION;

void help(char *s);
namespace Fahrenheit
{
    float FK(float F) {
        return ((5.0/9.0) * (F - 32.0) + 273.15);
    }

    float FC(float F) {
        return ((5.0/9.0) * (F - 32.0));
    }

    void printfahr(float F) {
        std::cout << "FAHR\t\tCELSIUS\t\tKELVIN" << std::endl;
        std::cout << F << "\t\t" << FC(F) << "\t\t" << FK(F) << std::endl;
    }      
}

namespace Celsius
{
    float CF(float C) {
        return ((C*(9/5)) + 32);
    }
    float CK(float C) {
        return (C+273.15);
    }
    void printc(float C) {
        std::cout << "FAHR\t\tCELSIUS\t\tKELVIN" << std::endl;
        std::cout << CF(C) << "\t\t" << C << "\t\t" << CK(C) << std::endl;
    }
}

namespace Kelvin
{
    float KF(float K) {
        return (((9.0/5.0) * (K-273.15)) + 32);
    }    
    float KC(float K) {
        return (K-273.15);
    }    
    void printk(float K) {
        std::cout << "FAHR\t\tCELSIUS\t\tKELVIN" << std::endl;
        std::cout << KF(K) << "\t\t" << KC(K) << "\t\t" << K << std::endl;
    }
}
int main(int argc, char *argv[])
{
    char arg = '\0';
    if(argc < 2 && argc == 1 && argc > 0) {
        help(argv[0]);
        exit(1);
    }
    /*** Use function getopt() defined in unistd.h to accept 5 arguments: -v, -h, -k, -f, and -c ***/
    while((arg=getopt(argc, argv, OPTS))!=-1)
    {
        float floatarg = atof(optarg);                                                      
        switch(arg)
        {

            case 'v':
                std::cout << "The current version is:" << ver << std::endl;
            break;

            case 'h':
                HELP;
            break;

            case 'k':
                Kelvin::printk(floatarg);
            break;

            case 'f':
                Fahrenheit::printfahr(floatarg);
            break;

            case 'c':
                Celsius::printc(floatarg);
            break;

            default:
                HELP;
            break;
        }
    }
    return 0;
}

void help(char *s) {
    std::cout << "Usage:\t"<< s << " [-option] [argument]" << std::endl;
    std::cout << "option:\t" << "-c [temperature]: convert a Celsius temperature to Fahrenheit and Kelvin" <<  std::endl;
    std::cout << "\t" << "-f [temperature]: convert a Fahrenheit temperature to Celsius and Kelvin" << std::endl;
    std::cout << "\t" << "-h: show help information" << std::endl;
    std::cout << "\t" << "-k [temperature]: convert a Kelvin temperature to Fahrenheit and Celsius" << std::endl;
    std::cout << "\t" << "-v: show version information" << std::endl;
}

我的问题是,每当我使用不接受任何参数的选项(如 -v)时,我都会得到核心转储。

dbx 告诉我 SIGSEV 出现在第 70 行 (float floatarg = atof(optarg);)。

当我这样运行程序时:

./F2C -k 273.15

数学计算正确,我得到了清晰的打印输出。只有当我使用-v 或-h 时,我的程序才会使用SIGSEV。

额外信息:

该程序是使用 Sun Studio 编译器套件 5.12 版编译的。

我完全困惑为什么我的程序是 SIGSEV。这是不一致的,没有任何意义。 如有任何帮助,我将不胜感激。

【问题讨论】:

  • 您希望为每个选项提供float 参数吗?
  • @user0042 不,但如果浮动 arg 永远不会......没关系。

标签: c++ std atof unistd.h


【解决方案1】:

应该做一些optarg检查。毕竟,您不能将null 转换为浮点数。

新的主():

#define FLOATARG atof(optarg)

int main(int argc, char *argv[])
{
    char arg = '\0';
    if(argc < 2 && argc == 1 && argc > 0) {
        help(argv[0]);
        exit(1);
    }
    /*** Use function getopt() defined in unistd.h to accept 5 arguments: -v, -h, -k, -f, and -c ***/
    while((arg=getopt(argc, argv, OPTS))!=-1)
    {                                                      
        switch(arg)
        {

            case 'v':
                std::cout << "The current version is:  << ver << std::endl;
            break;

            case 'h':
                HELP;
            break;

            case 'k':
                Kelvin::printk(FLOATARG);
            break;

            case 'f':
                Fahrenheit::printfahr(FLOATARG);
            break;

            case 'c':
                Celsius::printc(FLOATARG);
            break;

            default:
                HELP;
            break;
        }
    }
    return 0;
}

【讨论】:

  • 不鼓励在 c++ 中使用宏。
  • @user0042 为什么?定义一个符号常量并重用它比使用它背后的实际代码要好得多,因为该代码对于读者来说可能难以理解、含糊不清或两者兼而有之。 FLOATARG 比atof() 更容易理解。
  • “FLOATARG 比 atof() 更容易理解。” 这很有争议。你不应该混淆代码的作用。并且符号常量应该像constexpr float PI = 3.1414; 这样输入。
  • @user0042 我不敢苟同,Brian W. Kernighan 和 Dennis M. Ritchie 也一样。根据 C 编程语言的第二版,即 ANSI C,符号常量应该是#defined。
  • 1.这本书很老了。 2. 这与 C++ 无关。 C++ 和 C 是不同的编程语言,适用不同的规则和最佳实践。
【解决方案2】:

最短的修复方法是:

        float floatarg = optarg ? atof(optarg) : 0.0;

你也可以像这样重写你的代码

    float floatarg = 0.0;
    switch(arg)
    {

        case 'v':
            std::cout << "The current version is:" << ver << std::endl;
        break;

        case 'h':
            HELP;
        break;

        case 'k':
            floatarg = atof(optarg);
            Kelvin::printk(floatarg);
        break;

        case 'f':
            floatarg = atof(optarg);
            Fahrenheit::printfahr(floatarg);
        break;
...

或

    float floatarg = 0.0;
    if(optarg) {
        floatarg = atof(optarg);
    }
    switch(arg)
    {

        case 'v':
            std::cout << "The current version is:" << ver << std::endl;
        break;

        case 'h':
            HELP;
        break;

        case 'k':
            Kelvin::printk(floatarg);
        break;

        case 'f':
            Fahrenheit::printfahr(floatarg);
        break;
...

【讨论】:

    猜你喜欢
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 2015-05-12
    • 2017-08-13
    • 2021-02-16
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多