请问“ variableName;” C ++语句始终是空手吗? [英] Will a "variableName;" C++ statement be a no-op at all times?

查看:74
本文介绍了请问“ variableName;” C ++语句始终是空手吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++中,有时会定义一个变量,但不会使用。这是一个示例-与 COM_INTERFACE_ENTRY_FUNC_BLIND ATL宏:

  HRESULT WINAPI blindQuery(void * / * currentObject * /,REFIID iid,void ** ppv,DWORD_PTR / * param * /)
{
DEBUG_LOG(__FUNCTION__); // DEBUG_LOG宏在非调试
中扩展为空字符串DEBUG_LOG(iid);
iid; //<<<<<< --------静默编译器警告
if(ppv == 0){
return E_POINTER;
}
* ppv = 0;
返回E_NOINTERFACE;
}

在上面的示例中, iid 参数与 DEBUG_LOG 宏一起使用,该宏在非调试配置中扩展为空字符串。因此,注释掉或删除签名中的 iid 变量名是不可行的。编译非调试配置时,编译器会生成 C4100:'iid':未引用的形式参数警告,因此为了使警告静音,请使用 iid; 被认为是无操作的语句被添加。



问题如下:如果我们有以下任何一项声明:

  CSomeType variableName; //或
CSomeType&变量名; //或
CSomeType * variableName;

将在C ++代码中显示以下语句:

  variableName; 

始终保持无操作状态,独立于 CSomeType 是吗?

解决方案

是的,但是您可能还会收到另一个警告。



执行此操作的标准方法是:(void)iid;






从技术上讲,这仍然可以将 iid 加载到寄存器中并且什么也不做。当然,在编译器方面这是非常愚蠢的(如果确实删除了编译器,我怀疑有人会这么做),但是如果要忽略的表达式涉及可观察到的行为(例如调用IO函数或读取和写入 volatile 变量。



这提出了一个有趣的问题:我们能否接受表达式和完全忽略它吗?



也就是说,我们现在所拥有的是:

  #define USE(x)(void)(x)

//在表达式中使用iid摆脱警告,但没有明显的效果
USE(iid);

// hm,表达式的结果消失了,但表达式仍被评估
USE(std :: cout<<< hmmm<< std :: endl);

这接近解决方案:

  // sizeof不评估表达式
#定义USE(x)(void)(sizeof(x))

但失败:

  void foo(); 

//哎呀,不能采用sizeof void
USE(foo());

解决方案是简单地:

  //将表达式用作子表达式,
//然后将类型变为全表达式int,丢弃结果
#定义USE(x)(void)(sizeof( (x),0))

其中的任何操作均不保证。



编辑:以上内容确实没有效果,但我没有进行测试就发布了。经过测试,它至少在MSVC 2010中会再次生成警告,因为未使用 value




提醒:我们想使用一个表达式而不对其求值。如何才能做到这一点?像这样:

  #define USE(x)((void)(true?0:(x)))

像上次一样,有一个简单的问题(实际上更糟),其中(x) 需要可转换为 int 。再次解决这个问题很简单:

  #define USE(x)((void)(true?0:(( x),0)))

我们又回到了上次的效果(无),但这一次 x 被使用,所以我们没有收到任何警告。完成了,对吧?



实际上,此解决方案仍然存在一个问题(并且在上一个未解决方案中也存在,但没有引起注意),并且出现了在此示例中:

  struct foo {}; 
void运算符,(const foo& ;, int){}

foo f;
USE(f); //糟糕,void无法转换为int!

也就是说,如果表达式的类型(x)将逗号运算符重载为不可转换为 int 的值,解决方案失败。当然,不太可能,但是为了完全落伍,我们可以使用以下方法修复它:

  #define USE(x)( (void)(true?0:(((x),void(),0))))

为了确保我们最终得到零。 约翰内斯带给您的把戏






还应注意,如果以上内容还不够,那么足够愚蠢的编译器可能会装载表达式 0 (放入寄存器或其他内容),然后忽略它。



我认为这是不可能的,因为我们最终需要一个表达式来得出结果以某种方式可以忽略,但是如果我想到了,我将其添加。


In C++ sometimes a variable will be defined, but not used. Here's an example - a function for use with COM_INTERFACE_ENTRY_FUNC_BLIND ATL macro:

HRESULT WINAPI blindQuery( void* /*currentObject*/, REFIID iid, void** ppv, DWORD_PTR /*param*/ ) 
{
    DEBUG_LOG( __FUNCTION__ ); //DEBUG_LOG macro expands to an empty string in non-debug
    DEBUG_LOG( iid );
    iid; // <<<<<<<----silence compiler warning
    if( ppv == 0 ) {
        return E_POINTER;
    }
    *ppv = 0;
    return E_NOINTERFACE;
}

In the above example iid parameter is used with DEBUG_LOG macro that expands into an empty string in non-debug configurations. So commenting out or removing the iid variable name in the signature is not an option. When non-debug configurations are being compiled the compiler spawns a C4100: 'iid' : unreferenced formal parameter warning, so in order to silence the warning the iid; statement that is believed to be a no-op is added.

The question is the following: if we have any of the following declarations:

 CSomeType variableName; //or
 CSomeType& variableName; //or
 CSomeType* variableName;

will the following statement in C++ code:

variableName;

be a no-op at all times independent of what CSomeType is?

解决方案

Yes, but you'll likely get another warning.

The standard way of doing this is: (void)iid;.


Very technically, this could still load iid into a register and do nothing. Granted that's extremely stupid on the compilers part (I doubt any would ever do that, if it does delete the compiler), but it's a more serious issue if the expression to be ignored is something concerning observable behavior, like calls to IO functions or the reading and writing of volatile variables.

This brings up an interesting question: Can we take an expression and completely ignore it?

That is, what we have now is this:

#define USE(x) (void)(x)

// use iid in an expression to get rid of warning, but have no observable effect
USE(iid); 

// hm, result of expression is gone but expression is still evaluated
USE(std::cout << "hmmm" << std::endl);

This is close to a solution:

// sizeof doesn't evaluate the expression
#define USE(x) (void)(sizeof(x))

But fails with:

void foo();

// oops, cannot take sizeof void
USE(foo());

The solution is to simply:

// use expression as sub-expression,
// then make type of full expression int, discard result
#define USE(x) (void)(sizeof((x), 0))

Which guarantees no operation.

Edit: The above indeed guaranteed no effect, but I posted without testing. Upon testing, it generates a warning again, at least in MSVC 2010, because the value isn't used. That's no good, time for more tricks!


Reminder: We want to "use" an expression without evaluating it. How can this be done? Like this:

#define USE(x) ((void)(true ? 0 : (x)))

This has a simple problem like last time (worse actually), in that (x) needs to be be convertible to int. This is, again, trivial to fix:

#define USE(x) ((void)(true ? 0 : ((x), 0)))

And we're back to same kind of effect we had last time (none), but this time x is "used" so we don't get any warnings. Done, right?

There is actually still one problem with this solution (and was present in the last un-solution as well, but went unnoticed), and it comes up in this example:

struct foo {};
void operator,(const foo&, int) {}

foo f;
USE(f); // oops, void isn't convertible to int!

That is, if the type of the expression (x) overloads the comma operator to something not convertible to int, the solution fails. Sure, unlikely, but for the sake of going completely overboard, we can fix it with:

#define USE(x) ((void)(true ? 0 : ((x), void(), 0)))

To make sure we really end up with zero. This trick brought to you by Johannes.


Also as noted, if the above wasn't enough, a stupid enough compiler could potentially "load" the expression 0 (into a register or something), then disregard it.

I think it's impossible to be rid of that, since we ultimately need an expression to result in a type of some sort to ignore, but if I ever think of it I'll add it.

这篇关于请问“ variableName;” C ++语句始终是空手吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆