C ++`if`似乎采取了错误的分支?

时间:2018-01-16 18:04:39

标签: c++ if-statement

我正在努力处理一个非感性的if语句......

在C ++文件中考虑此代码

if (coreAudioDevice) {
    delete coreAudioDevice;
    coreAudioDevice = nullptr;
}
coreAudioDevice = AudioDevice::GetDevice(defaultOutputDeviceID, false, coreAudioDevice, true);
if (coreAudioDevice)
{
    coreAudioDevice->setDefaultDevice(true);
    // we use the quick mode which skips initialisation; cache the device name (in AudioDevice)
    // using an immediate, blocking look-up.
    char devName[256];
    coreAudioDevice->GetName(devName, 256);

    AUDINFO ("Using default output device %p #%d=\"%s\".\n",
             defaultOutputDeviceID, coreAudioDevice, coreAudioDevice->GetName());
}
else
    AUDERR ("Failed to obtain a handle on the default device (%p)\n", coreAudioDevice);

调用ObjC ++文件中的函数:

AudioDevice *AudioDevice::GetDevice(AudioObjectID devId, bool forInput, AudioDevice *dev, bool quick)
{
    if (dev) {
        if (dev->ID() != devId) {
            delete dev;
        } else {
            return nullptr;
        }
    }
    dev = new AudioDevice(devId, quick, forInput);
    return dev;
}

导致以下终端输出:

ERROR coreaudio.cc:232 [init]: Failed to obtain a handle on the default device (0x7f81a1f1f1b0)

显然if不应该失败,因为coreAudioDevice据说是NULL,然后在else分支中为这个变量打印一个非null值。

我尝试了不同的编译器选项和不同的编译器(clang 4.0.1 vs. 5.0.1),显然我的代码中确实有些可疑。有什么想法吗?

3 个答案:

答案 0 :(得分:1)

在不返回值的情况下到达函数的末尾是C ++中未定义的行为。

请参阅http://en.cppreference.com/w/cpp/language/ubWhat are all the common undefined behaviours that a C++ programmer should know about?

所以致电setDefaultDevice()可以合法地产生任何结果。当程序的控制流导致未定义的行为(即调用setDefaultDevice())时,编译器可以自由地将程序编译成可执行任何操作的可执行文件。

在这种情况下,输入ifcoreAudioDevice非零会导致UB。所以优化编译器会预见到这一点,然后选择让它进入else分支。像这样它可以完全删除第一个分支和if,以产生更优化的代码。

请参阅https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633

如果没有优化,程序通常应按预期运行。

答案 1 :(得分:0)

好吧,至少我找到了一个理由,但还没有理解(还)。

我已经定义了这个方法,没有注意到编译器警告(由于并发编译而多次打印多次弃用警告......):

bool setDefaultDevice(bool isDefault)
{
    mDefaultDevice = isDefault;
}

确实,没有回报价值。

请注意,我在跳过的if块中调用此方法 - 所以理论上我从来没有机会这样做。什么导致我发现这个奇怪的问题。

当我移除呼叫或我按预期使方法无效时,问题就消失了。

我认为这也解释了我看到的非常奇怪的崩溃方式:不知何故,优化者因此而完全混淆了。我很想把它称为编译器错误;我没有使用该方法的返回值,因此不应该在所有恕我直言中影响流量。

答案 2 :(得分:0)

啊,对。我是否应该将其视为“可以自由地建立一个除了感性事物之外可以做任何事情的执行官”?如果是这样的话,那个我的前任老板有一个禁止C ++作为异常的观点(确切的说法是法语,“saleté”)......

无论如何,当你不知道函数实际上没有在堆栈上放置返回值时,我可以理解为什么行为将是未定义的。你会在返回后从堆栈中弹出字节,弄乱了。 (必要时读取堆栈的堆栈=])。我猜这是你在没有优化的情况下运行这种代码时会发生什么,在良好的ole C中或者在线外定义的bugggy方法(因此优化器不能知道它是错误的)。

但是一旦你知道一个函数实际上没有返回一个值,并且你看到该值无论如何都不会被使用,你应该能够发出不会弹出相应字节数的代码。 IOW,行为符合预期的代码。有一个很大的编译时警告。假定标准允许这样做是理所当然的事情,而不是优化整个受污染的块,因为它会更快。如果这确实是铿锵声中的推理,它实际上并没有激发信心......

标准是否说默认情况下这不是错误?我当然更喜欢当前的行为!