有没有更好的方法来评论代码中的参数方向?

时间:2012-03-02 06:43:19

标签: c++ readability

我想提高代码的可读性。所以我在代码中评论了参数的方向,如下所示:

#define IN
#define OUT

void Add(IN int Para1, IN int Para2, OUT int& Result);

但是我认为编译器会用空白替换IN和OUT的每个实例,有时可能会出现问题。

那么还有更好的方法吗?感谢。

(我使用C ++。)

9 个答案:

答案 0 :(得分:9)

您可以尝试将其放入评论中。这更好,更易读。

void Add(/*IN*/ int Para1, /*IN*/ int Para2, /*OUT*/ int& Result);

答案 1 :(得分:6)

是:忘掉那些东西并使用constness。只要您没有“输入”和“输出”参数,这将是有效的,这应该很少使用。

void foo(int i, const std::string& s, std::vector<char>& out_buf);
// i and s are obviously "in" variables, while out_buf could be both, 
// but you can easily show that by giving the parameter a proper name.

编辑: 而const正确性并不意味着使值参数成为常量!这根本不会给调用者任何额外的信息,因为你不能改变他的变量。

答案 2 :(得分:3)

我可以想到两个简单的方法......

1。

        /*Description : Function for adding the two variables.
        * Returns : Nothing 
        * Parameters : Para1 and Para2  are **IN** parameter and 
        * Result is an **OUT** parameter
        * @author : <put ur name here> 
        */
    void Add(IN int Para1, IN int Para2, OUT int& Result);

除了这些基本信息,您还可以存储版本号,创建日期等信息。

2. 您还可以使用变量名称嵌入参数类型信息,例如 inPara1,inPara2和outResult。,例如

 void Add(int inPara1,int inPara2,int& outResult);

我还建议使用驼峰大小写字母表示变量和函数名称,即Para1可以作为para1等,这将有助于您将来。

答案 3 :(得分:1)

您可以创建'IN'变量const,这意味着它们永远不会被修改,因此必须是仅输入变量。没有 a const的引用也可能表示它的内容已被修改,因此必须是'OUT'变量。但实际上,只要遵循一个好的变量命名约定就足够了。调用参数'Result'意味着它本身就是一个'OUT'变量。

编辑:正如其他人正确提到的那样,将像int这样的值作为const vars传递可能不是一个好主意。尽管如此,你应该能够通过它们总是需要引用(或指针)的绝对事实来推断变量是否是输出变量。通过使输入值为const的引用,这意味着所有非const的引用必须是输出值。

答案 4 :(得分:1)

我使用类似的东西

void Add(
    /* input parameters */
    int Para1,
    int Para2,
    /* output parameters */
    int& Result
);

这样可以轻松地为函数添加新参数,因为您不必使用输入输出标记每个参数,他们只需转到相应的部分

答案 5 :(得分:1)

鉴于这是一个风格问题,它会激起一些主观反应,包括我的。 : - )

那里有程序语言要求将函数参数定义为输入或输出。在C ++中,这在很大程度上是不必要的。

现代C ++开发人员应具备的一般思维方式是更多地关注可变与不可变,以及对原始类型和数据的接口。

当我们看一下这样的函数时:

void f(int x);

... C ++开发人员可以一眼就看出'x'用于输入。为什么?它正在被价值所传递。无法以对调用者有任何影响的方式修改“x”,因此不会修改传递给此函数的任何参数。

任何const引用都是如此:

void f(const Foo& read_only_foo);

以上绝对是一个严格的输入参数。当我们看一下这样的函数时:

void f(int& x);

我们通常可以假设f将修改x(不保证,但知道f做了什么应该清除任何疑问。)

使用用户定义的类型,它会变得更加模糊。

ostream& operator<<(ostream& os, const Foo& foo);

这里我们确定'foo'是一个输入参数,因为它是不可变的。但是'os'怎么样?它是输出参数,输入吗?在严格的过程语言中,输出参数通常意味着参数将被更改,但我们也在这里读取它,因此它们都是。虽然我们将在'os'中调用对其状态有影响的方法,但这并不完全是我们在过程语言中考虑输出参数的方式,这些参数本身支持in / out参数。

关键是这种严格的I / O思考参数的方式可以完全混淆这些高级接口和面向对象的设计。在这里查看事物的更有用的方法往往是实现接口的对象是可变的还是不可变的。在这里,'os'是可变的。该函数通常说它将调用一些修改其状态的函数。

这个怎么样?

// fills the specified list with stuff
void some_list(list<int>& out_list);

在这里,它可能更自然地与我们期望的输出参数的语义一起出现。通过填充列表等内容,我们倾向于更直观地将其视为通过列表输出结果的函数。我甚至用'out'作为名称前缀,以强调这一点。但实际上,特别是对于C ++ 11,我们不应该写Stroustrup强调的东西:

// returns a new list filled with stuff
list<int> some_list();

这实际上留下了很少的位置,其中输入/输出区别可以说是非常有用的(并且没有多余的已经提供的方法将参数标记为可变/不可变,通过值,参考,指针或r-价值参考)。

结合关于函数正在做什么的清晰文档,通常没有关于它如何与其参数一起工作的模糊性,因此in / out约定往往做很少但添加了大量额外代码,并且可能会促进更多你应该试图摆脱的以数据为导向的思维方式。

总而言之,我建议尽量避免这种惯例。即使有好的论据支持它,也不是人们在C ++中倾向于做的事情。如果您希望人们喜欢使用您的代码并且不会感到沮丧,那么您必须学会接受普通群众倾向于理解和喜欢的内容。任何过于异国情调的东西都会吓跑人们。

如果你绝对,狂热地依赖于将所有内容指定为 in out ,我建议采用最低限度的侵入式解决方案,如文档样式或命名约定。绝对避免无所事事的宏。这将要求您的读者每次检查这些宏时都会检查,实际上什么都不做。命名约定或文档样式不需要这样的检查。

最后,来自C ++自己的创造者的一句话:

  

关于宏的第一条规则是:除非必须,否则不要使用它们。   几乎每个宏都在编程语言中表现出一个缺陷   程序,或程序员。 - Bjarne Stroustrup

答案 6 :(得分:0)

这有两个方面:功能签名和呼叫站点。你专注于签名,所以我先解决这个问题。注意:

  • const通过函数
  • 传达并强制执行可能的修改
  • 为库提供一致的API约定可以帮助库和客户端代码程序员,例如:
    • 返回输出(可能意味着必须使用元组,容器或自定义结构),同时保留输入的函数参数。
    • 通过标识符和参数排序表示关于函数的内容;就个人而言,如果我编写一个可能改变参数的函数,我倾向于将该函数命名为loadXXX()并将输出放在第一位。我见过的其他图书馆一直把输出放在最后。这是一个随意的选择,但一致性有帮助。同样,您可以以不同的方式命名输出参数....
  • 评论/文档

在客户端调用站点,当传递非const参数时,不清楚它可能会发生什么。

  • 同样,loadXXX,组输出第一个/最后一个,更喜欢 - return - 输出 - getXXX - 上面提到的约定也帮助客户。
  • 通过指针传递输出参数是一项历史悠久但有争议的做法,IMO在当前的专业C ++程序员中并不是特别受欢迎,但可以很好地阅读并增加真正的价值。 C ++ FAQ解决了大多数问题,但得出了与我不同的结论。
  • 您可以将非const参数投射到const,以便在呼叫网站上进行通信,告知他们不会被修改,但这样做既繁琐又乏味,而且这种做法无法通过编译器(编译器将阻止被调用函数修改这些参数,但不强制调用者提供函数接受的参数const以明确地将其转换为const)。

使用代理对象可以“强制”使用其中一些内容,但这会使您的代码几乎无法读取且无法维护。

答案 7 :(得分:0)

使用适当的语言结构,而不是工件。

使用IN和OUT不会授予他们真正 IN和OUT。这就像匈牙利的符号,称WPARAMword,今天为long

  • 传递值(int)是一个可以修改的IN
  • 传递const ref(const int&)是一个IN,在函数中表现为常量
  • 通过引用传递(int&)是必须存在的OUT
  • 传递一个const指针(const int*)是一个IN,也可以不给(空指针)
  • 传递指针(int*)是一个OUT,也可以不给出(空指针)

使用正确的语言构造的好处是,不正确的使用将导致编译错误(因此您被迫纠正问题)而IN和OUT将永远不会在代码中产生任何类型的错误,并且您可能会介绍一个正式的惯例 - 在一定数量的维护版本之后 - 甚至可以说谎。

答案 8 :(得分:0)

您可以将Microsoft的SAL表示法用于C ++:

https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ms235402(v=vs.100)

来自文档:

_In _

该功能将仅从缓冲区读取。调用者必须提供缓冲区并对其进行初始化。

_Out _

该函数将只写入缓冲区。调用者必须提供缓冲区,然后函数将对其进行初始化。

_Inout _

该函数可以自由读取和写入缓冲区。调用者必须提供缓冲区并对其进行初始化。

_Deref_out _

适用于已取消引用的输出参数。给定参数p,* p是缓冲区指针。 p不能为NULL。

该函数将只写入缓冲区。该函数将提供缓冲区并对其进行初始化。