首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >去掉一个丑陋的C结构

去掉一个丑陋的C结构
EN

Stack Overflow用户
提问于 2014-05-05 11:19:16
回答 3查看 418关注 0票数 4

我继承了一段(大的)代码,它有一个错误跟踪机制,其中将布尔变量传递给它们调用的所有方法,在执行的不同阶段,该方法被停止并返回,有时是一个默认值。

类似于(以前)的事情:

代码语言:javascript
复制
#include <iostream.h>
int fun1(int par1, bool& psuccess)
{
    if(par1 == 42) return 43;
    psuccess = false;
    return -1;
}
int funtoo(int a, bool& psuccess)
{
    int t = fun1(a, psuccess);
    if(!psuccess)
    {
        return -1;
    }
    return 42;
}
void funthree(int b, bool& psuccess)
{
    int h = funtoo(b, psuccess);
    if(!psuccess)
    {
         return;
    }
    cout << "Yuppi" << b;
}
int main()
{
    bool success = true;
    funthree(43, success);
    if(!success)
    {
        cout<< "Life, universe and everything have no meaning";
    }
}

请注意,这是C和C++代码的混合物,这正是项目的方式。

现在,出现了一个C魔术:“某人”定义了一个宏:

代码语言:javascript
复制
#define SUCCES_OR_RETURN  if(!psuccess) return

上面的程序变成(后):

代码语言:javascript
复制
#include<iostream.h>
int fun1(int par1, bool& psuccess)
{
    if(par1 == 42) return 43;
    psuccess = false;
    return -1;
}
int funtoo(int a, bool& psuccess)
{
    int t = fun1(a, psuccess);
    SUCCES_OR_RETURN -1;
    return 42;
}
void funthree(int b, bool& psuccess)
{
    int h = funtoo(b, psuccess);
    SUCCES_OR_RETURN ;
    std::cout << "Yuppi" << b;
}
int main()
{
    bool success = true;
    funthree(43, success);
    if(!success)
    {
        cout<< "Life, universe and everything have no meaning";
    }
}

问题是:我想知道是否有一种更好的方法来处理这种错误跟踪,或者我必须接受这一点。我个人不喜欢滥用CSUCCES_OR_RETURN ie。一旦用参数调用它,在其他情况下调用它时,它就像一个真正的return语句,但是我没有找到更好的解决方案来解决这个古老的设计。

请注意,由于平台的限制,我们有几个限制,但无论如何,我愿意听取关于这两个方面的意见:

  • 抛出异常。代码是C函数和C++函数相互调用的混合体,编译器不支持throw (语法上接受,但不做任何操作,只是警告)。这个解决方案是在C++环境中解决这个问题的标准方法。
  • C++11特性,这是一个微小的嵌入式平台,它有一个晦涩而古老的“几乎”C++编译器,它不是为支持最新的C++特性而设计的。不过,为了将来的参考,我是好奇,如果有任何C++11提供的东西。
  • 模板魔法。编译器在理解复杂的模板问题方面有问题,但我还是愿意看到任何您能想出的解决方案。

编辑

此外,正如@BlueMoon在推荐中所建议的,创建一个全局变量是行不通的,因为在调用success变量的函数链的一开始,调用该变量的是类的一个成员变量,并且创建了该类的几个对象,每个对象都需要报告其成功状态:)

EN

回答 3

Stack Overflow用户

发布于 2014-05-05 11:27:07

在这里,混合C和C++错误处理策略出现了很大的故障:

  • http://blog.sduto.it/2014/05/a-c-error-handling-style-that-plays.html

引用链接文章,您的选项基本上可以归结为:

  • 从可能失败的函数返回错误代码。
  • 提供类似于Windows的GetLastError()或OpenGL的glGetError()之类的函数来检索最近出现的错误代码。
  • 提供一个全局变量(希望是线程局部变量),其中包含最近的错误,比如POSIX的errno。
  • 提供一个函数来返回有关错误的更多信息,可能与上述方法之一结合使用,比如POSIX的strerror函数。
  • 允许客户端在发生错误时注册回调,如GLFW的glfwSetErrorCallback
  • 使用特定于操作系统的机制,如结构化异常处理。
  • 将错误写入日志文件、stderr或其他地方。
  • 只需在发生错误时断言()或以某种方式终止程序。

似乎您继承的代码的作者选择了一种非常奇怪的方式,传递一个指向布尔值的指针以供函数使用似乎很不寻常。

这篇文章有一些很好的例子,我个人喜欢这种风格:

代码语言:javascript
复制
libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
if (libfoo_create_widgets(12, &container, &error) != libfoo_success) {
    printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
    libfoo_error_details_free(error);
    abort(); // goodbye, cruel world!
}

在这里,您得到了所有的东西,传入了指向错误类型的指针,这是与成功常量的比较(而不是0|1,这是C和世界其他地方之间痛苦的二分法!)

我不认为用goto更好地实现宏并不是太大的推动,无论如何,如果一个函数不止一次调用SUCCES_OR_RETURN,它可能是函数做得太多的线索。复杂的清理,或者返回可能是一种代码气味,您可以在这里阅读更多的http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/

票数 5
EN

Stack Overflow用户

发布于 2014-05-05 14:23:23

我以前见过这种错误处理方式。我称它为错误-不经意的人工伪异常。

代码流主要是错误--忽略:您可以使用相同的错误标志在一行中调用3个函数,然后查看错误标志,看看是否发生了任何错误。

错误标志充当伪异常,一旦设置,我们就开始在正常代码流上“跳过”,但是这是手动完成的,而不是自动完成的。

如果您做了一些事情,而不关心是否发生了错误,您可以直接删除所产生的错误并继续进行。

ICU图书馆以类似的方式处理错误。

要做到这一点,同时最小化结构差异,更多的C++1y方法是修改代码以返回expected对象。

一个expected<T, Err>应该是一个T,如果出了什么问题,它将是一个Err类型。这可以实现为boost::variant和C++1Y的std::optional的混合。如果要对expected< T, Err > + U上的大多数算术操作进行重载以返回expected< decltype( std::declval<T&>() + std::declval<U>(), Err >,并执行了一些谨慎的auto操作,则至少可以允许算术表达式保持其结构。然后,您将检查该事实之后的错误。

另一方面,如果错误返回值基于其类型是可预测的,则可以创建一个类型,当转换到给定类型时会产生错误值。修改返回void的函数,以便在您访问它时返回某种错误对象。现在每个函数都可以

代码语言:javascript
复制
if (berror) return error_flag_value{};

它至少能解决那个奇怪的;-1;问题。

票数 3
EN

Stack Overflow用户

发布于 2014-05-05 13:14:12

如果您想使用完整的C++,答案将是更改异常的“无效返回值”.

代码语言:javascript
复制
#include <iostream>
#include <exception>

using std::exception;

struct error : exception { const char* what() const throw() override { return "unsuccessful"; } };

int fun1(int par1) {
  if( par1 == 42 ) return 43;
  throw error();
}

int funtoo(int a) {
  fun1(a);
  return 42;
}

void funthree(int b) {
  funtoo(b);
  std::cout << "Yuppi " << b << "\n";
}

int main() {
  try {
    funthree(42);
  } catch(exception& e) {
    std::cout << "Life has no meaning, because " << e.what() << "\n";
  }
}

这将打印Yuppi 42 (如果更改funthree(43)的调用funthree(42),则会打印Life has no meaning, because unsuccessful.)

(住在coliru)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23471187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档