【问题标题】:Why does this use of assignment operator in a function argument fail?为什么在函数参数中使用赋值运算符会失败?
【发布时间】:2017-10-11 04:49:31
【问题描述】:

有人能指出为什么,在下面的代码中,为什么在传递给write() SIGSEGVs 时使用具有“返回右值”样式的变量p_char

#include <iostream>
#include <cerrno>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdint.h>
#include <sstream>
#include <stdexcept>

#define ASSERT( EXPRESSION, SOCKETPAIR ) \
{ \
  if ( ! ( EXPRESSION ) ) \
  { \
    std::ostringstream oss; \
    oss << "Expression \"" << #EXPRESSION << "\" failed at line " << __LINE__ \
        << "; errno == " << errno << " (" << strerror( errno ) << ")"; \
    throw MyException( oss.str(), SOCKETPAIR ); \
  } \
}

class SocketPair
{
public:
  SocketPair()
  {
    memset( socket_, -1, sizeof( socket_ ) );
  }
  int* operator()() { return socket_; }
  int operator[]( const uint32_t idx )
  {
    if ( idx > 1 ) return -1;
    return socket_[ idx ];
  }
private:
  int socket_[ 2 ];
};

class MyException : public std::runtime_error
{
public:
  MyException( const std::string& what_arg, SocketPair& sp )
    : runtime_error( what_arg )
    , sp_( sp )
  {}
  SocketPair& sp_;
};

int main( int argc, char* argv[] )
{
  SocketPair sp;
  try
  {
    int result;

    errno = 0;
    result = socketpair( AF_LOCAL, SOCK_STREAM, 0, sp() );
    ASSERT( result == 0, sp );

    std::cout << "sp[0]==" << sp[0] << ", sp[1]==" << sp[1] << std::endl;

    const char* p_char;
    result = write( sp[ 1 ], ( p_char = "Hello?" ), strlen( p_char ) );
    ASSERT( result == strlen( p_char ), sp );
  }
  catch ( MyException& e )
  {
    std::cout << e.what() << std::endl;
    if ( e.sp_[ 0 ] >= 0 ) close( e.sp_[ 0 ] );
    if ( e.sp_[ 1 ] >= 0 ) close( e.sp_[ 1 ] );
    return 1;
  }

  close( sp[ 0 ] );
  close( sp[ 1 ] );
  return 0;
}

如果我更改以下两行...

const char* p_char;
result = write( sp[ 1 ], ( p_char = "Hello?" ), strlen( p_char ) );

...到这个...

const char* p_char = "Hello?";
result = write( sp[ 1 ], p_char, strlen( p_char ) );

...然后程序不 SIGSEGV 并优雅退出。

在 gcc 4.8.3 和 4.9.2 (Code Chef) 上测试编译。

【问题讨论】:

  • “返回右值”是什么意思?什么右值?
  • @M.M - 右值是 const char* "Hello?"。在这篇 stackoverflow 文章中,我看到了这种称为“返回右值”的代码模式:stackoverflow.com/questions/9514569/…。为func( foo = &lt;some rvalue&gt; ) 的模式,即foo 分配了右值,然后将该值传递给func。是否有另一个/更合适的术语?
  • 好的。那是糟糕的术语,我已经编辑了其他答案。 "Hello?" 是一个左值(左值可以出现在= 的右侧)。
  • @M.M - 你知道有没有定义左值和右值的权威文章?我已经看到 rvalues 被模糊地定义为“出现在赋值运算符右侧的无名 const 对象”,包括在 StackOverflow 上,所以我会接受它作为我的理解。但你所说的与此相矛盾。
  • 是的,C 标准。您可以通过搜索“n1570”找到副本。该标准实际上甚至没有使用术语“右值”,但在 C 语言的上下文中,它经常被用来表示“不是左值的值”。 (“左值”由标准定义)。 ,如果您对“右值”进行文本搜索,则会有一个脚注。

标签: c++ variable-assignment segmentation-fault rvalue


【解决方案1】:

函数参数的求值顺序未定义(至少在 C++14 及更早版本中)。

所以在

result = write( sp[ 1 ], ( p_char = "Hello?" ), strlen( p_char ) );

strlen( p_char ) 可能在p_char = "Hello?" 之前被评估,导致灾难。

【讨论】:

  • 哦,这对我来说是新的,我很久以前就形成了这样的观点,即函数参数是从左到右评估的。我学到了一些新东西;谢谢。
猜你喜欢
  • 2013-07-24
  • 2011-05-21
  • 2019-02-05
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 2014-05-29
相关资源
最近更新 更多