当前位置:  开发笔记 > 编程语言 > 正文

C逗号运算符的使用

如何解决《C逗号运算符的使用》经验,为你挑选了10个好方法。

你看到它用于for循环语句,但它在任何地方都是合法的语法.您在其他地方找到了什么用途,如果有的话?



1> AnT..:

C语言(以及C++)历史上是两种完全不同的编程风格的混合,可以称之为"语句编程"和"表达式编程".如您所知,每种过程编程语言通常都支持诸如排序分支之类的基本结构(参见结构化编程).这些基本结构以两种形式存在于C/C++语言中:一种用于语句编程,另一种用于表达式编程.

例如,当您根据语句编写程序时,可以使用由...分隔的语句序列;.如果要进行分支,可以使用if语句.您还可以使用循环和其他类型的控制转移语句.

在表达式编程中,您也可以使用相同的结构.这实际上是,运营商发挥作用的地方.运算符,只不过是C中顺序表达式的分隔符,即,表达式编程中的运算符与语句编程中的作用相同;.在表达式编程分枝是通过完成?:运营商和,可选地,通过短路评价特性&&||操作符.(表达式编程虽然没有循环.要用递归替换它们,你必须应用语句编程.)

例如,以下代码

a = rand();
++a;
b = rand();
c = a + b / 2;
if (a < c - 5)
  d = a;
else
  d = b;

这是传统语句编程的一个例子,可以用表达式编程重写

a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? d = a : d = b;

或者作为

a = rand(), ++a, b = rand(), c = a + b / 2, d = a < c - 5 ? a : b;

要么

d = (a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? a : b);

要么

a = rand(), ++a, b = rand(), c = a + b / 2, (a < c - 5 && (d = a, 1)) || (d = b);

毋庸置疑,在实践中,语句编程通常会产生更易读的C/C++代码,因此我们通常使用非常好的测量和限制量的表达式编程.但在许多情况下它会派上用场.在可接受和不可接受之间的界限在很大程度上取决于个人偏好以及识别和阅读既定习语的能力.

另外需要注意的是:语言的设计显然是针对陈述而定制的.语句可以自由地调用表达式,但表达式不能调用语句(除了调用预定义的函数).这种情况在GCC编译器中以一种相当有趣的方式改变,它支持所谓的"语句表达式"作为扩展(与标准C中的"表达式语句"对称)."语句表达式"允许用户直接将基于语句的代码插入到表达式中,就像它们可以将基于表达式的代码插入到标准C中的语句中一样.

另外还有一点需要注意:在C++语言中,基于仿函数的编程起着重要的作用,可以看作是另一种形式的"表达式编程".根据C++设计的当前趋势,在许多情况下,它可能比传统的语句编程更受欢迎.



2> Jack Lloyd..:

我认为通常C的逗号不是一个好用的风格,因为它非常容易被错过 - 要么是其他人试图阅读/理解/修复你的代码,要么是你自己一个月下来.当然,在变量声明和for循环之外,它是惯用的.

例如,您可以使用它将多个语句打包成三元运算符(?:),ala:

int x = some_bool ? printf("WTF"), 5 : fprintf(stderr, "No, really, WTF"), 117;

但是我的天哪,为什么?!?(我已经看到它在实际代码中以这种方式使用,但不幸的是无法访问它)


这当然很棘手,因为你将逗号与声明中的逗号混合使用xD现在,无论是否合法 - 我不知道但标准知道:)事实是:你需要使用'op?的第三个操作数: `,因为否则绑定是:`int x =(cond?A:B),117;`xD
整蛊,我不知道这个.C(++)确实有太多的"功能",这些功能对任何事情都没有好处,但会在鸡尾酒会上引起无穷无尽的愚蠢笑声.
我有点难过,你不想解决它.我知道您希望将答案保持在"零编辑"状态.但是,为了保持产生编译错误的代码的代价,例如"数字常量之前的预期不合格ID",我认为这不是有益的.如果您想让代码混淆,您还可以编写任何其他非编译代码.我认为重点是代码混淆*和*编译.
答案中存在严重的术语错误.您不能在标准C中"将多个*语句*打包成三元运算符".您在上面"打包成三元运算符"不是*语句*.这些子表达式由`,`运算符连接成一个更大的表达式."陈述"是C中的一个重要概念,滥用这个词只会导致不必要的混淆.
这样做的最好理由是初始化一个常量变量,因为你不能做`const int x; if(some_bool){printf("WTF"); X = 5; } else {fprintf(stderr,"不,真的,WTF"); X = 117; 但是,我仍然同意你的例子不是很漂亮和/或可读.
+1因为它太邪恶了

3> Adisak..:

我已经看到它在宏中使用,宏假装是一个函数,想要返回一个值,但需要先做一些其他的工作.它总是丑陋的,虽然看起来像是一个危险的黑客.

简化示例:

#define SomeMacro(A) ( DoWork(A), Permute(A) )

这里B=SomeMacro(A)"返回"Permute(A)的结果并将其分配给"B".


+1尽管我不同意它是丑陋和危险的.只需谨慎声明您的宏,您就安全了

4> P Shved..:

C++中的两个杀手逗号运算符功能:

a)从流中读取直到遇到特定字符串(有助于保持代码DRY):

 while (cin >> str, str != "STOP") {
   //process str
 }

b)在构造函数初始化器中编写复杂代码:

class X : public A {
  X() : A( (global_function(), global_result) ) {};
};


您的第二个示例需要另一对括号,以防止逗号充当构造函数参数分隔符.(我想你并不打算这样做).
@ UncleBens,`cin >> str`返回`iostream`,当到达文件结束时将转换为`false`布尔值,而不是在遇到空字符串时!
这是不是意味着你的代码会卡在文件的最后一行?cin >> str不会覆盖str(我认为?),而str!=""将永远是真的.
@litb,修复,谢谢.

5> fa...:

我必须使用逗号来调试互斥锁,以便在锁开始等待之前发送消息.

我不得不在派生锁构造函数体中的日志消息,所以我不得不在初始化列表中使用:baseclass((log("message"),actual_arg))将它放在基类构造函数的参数中.注意额外的括号.

这是类的摘录:

class NamedMutex : public boost::timed_mutex
{
public:
    ...

private:
    std::string name_ ;
};

void log( NamedMutex & ref__ , std::string const& name__ )
{
    LOG( name__ << " waits for " << ref__.name_ );
}

class NamedUniqueLock : public boost::unique_lock< NamedMutex >
{
public:

    NamedUniqueLock::NamedUniqueLock(
        NamedMutex & ref__ ,
        std::string const& name__ ,
        size_t const& nbmilliseconds )
    :
        boost::unique_lock< NamedMutex >( ( log( ref__ , name__ ) , ref__ ) ,
            boost::get_system_time() + boost::posix_time::milliseconds( nbmilliseconds ) ),
            ref_( ref__ ),
            name_( name__ )
    {
    }

  ....

};



6> Stjepan Rajk..:

所述升压分配库是在一个有用的,可读的方式重载逗号操作符的一个很好的例子.例如:

using namespace boost::assign;

vector v; 
v += 1,2,3,4,5,6,7,8,9;



7> 小智..:

从C标准:

逗号运算符的左操作数被计算为void表达式; 评估后有一个序列点.然后评估右操作数; 结果有它的类型和价值.(逗号运算符不会产生左值.))如果尝试修改逗号运算符的结果或在下一个序列点之后访问它,则行为未定义.

简而言之,它允许您指定多个表达式,其中C只需要一个.但实际上它主要用于循环.

注意:

int a, b, c;

不是逗号运算符,它是一个声明符列表.


问题是关于何时使用它,而不是它的用途
`int a,b,c;`中没有"初始化器".在`int a,b,c;`逗号分隔*声明符*.

8> SadSido..:

你可以重载它(只要这个问题有一个"C++"标签).我看过一些代码,其中重载的逗号用于生成矩阵.或矢量,我不记得确切.不是很漂亮(虽然有点令人困惑):

MyVector foo = 2,3,4,5,6;


重要说明:如果重载逗号运算符,则会松开序列点,即.您将获得函数调用语义,并且操作符的操作数将以未指定的顺序进行计算.

9> Thomas Padro..:

它有时用在宏中,例如调试宏,如下所示:

#define malloc(size) (printf("malloc(%d)\n", (int)(size)), malloc((size)))

(但是,真实地看看这个可怕的失败,因为当你过度时会发生什么.)

但除非你确实需要它,或者你确信它使代码更具可读性和可维护性,否则我建议不要使用逗号运算符.



10> jmucchiello..:

在for循环之外,甚至可以有代码气味的香气,我看到的唯一一个用于逗号运算符的地方是删除的一部分:

 delete p, p = 0;

替代方案的唯一值是,如果它在两行上,你可以意外地复制/粘贴这个操作的一半.

我也喜欢它,因为如果你出于习惯,你永远不会忘记归零.(当然,为什么p不在某些auto_ptr,smart_ptr,shared_ptr等包装器内部是一个不同的问题.)


那么在"删除"之后将指针设置为null的好处是非常有争议的......
推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有