Определения препроцессора работают в режиме Release, а не в Debug - PullRequest
0 голосов
/ 18 апреля 2019

Я пытаюсь получить макрос препроцессора, который будет определен в одном исходном файле hw_model.cpp, и оставить его неопределенным в другом, main.cpp.

Когда я запускаю эту программу в режиме x64 Release (Visual Studio 2017), все в порядке. Когда я запускаю в режиме отладки x64, оператор #undef ACT_LIKE_HARDWARE в main.cpp, похоже, игнорируется.

model.h:

extern Signal signal;
void setSignalsFromHw();


// code below is inside some function :
#ifdef ACT_LIKE_HARDWARE
    // perform a procedure that behaves like hardware
    // This C code is supposed to act like hardware
    // hardware has the freedom to write to read-only variables
#else
    // perform some other procedure that firmware can normally do
#endif

main.cpp:

#undef ACT_LIKE_HARDWARE

#include "model.h" 

Signals signal;

int main(){
    uint32_t read_data = signal.wv0;
    // do some processing on the read_data

    setSignalsFromHw();
}

hw_model.cpp:

#define ACT_LIKE_HARDWARE

#include "macro.h"

// Perform a cast on the "signal" global variable
// This cast operation is done so that "signal_HWModel" has the freedom to write to read-only fields
Signals_HWModel* signal_HWModel = reinterpret_cast<Signals*>(&signal);

void setSignalsFromHw(){
    ntfySignal_HWModel->wv0 = 0x2;
    ntfySignal_HWModel->wv1 = 0x4;
}

Во-первых, должен ли я определять макросы препроцессора в одних исходных файлах и отменять их определение в других? Если нет, то что было бы хорошим решением? Пожалуйста, примите во внимание тот факт, что model.h гораздо сложнее, чем я предполагаю, что он здесь, и его было бы несколько сложно изменить, но я определенно открыт для всех предложений.

Во-вторых, почему существует различие между работой в режиме отладки и выпуска?

Спасибо

-------------- ** ОБНОВЛЕНИЕ ** --------------

По запросу это минимальный исполняемый код. Это иллюстрирует ту же проблему, что у меня была выше. Извините, если выглядит немного иначе, чем выше. Я просто стараюсь не раскрывать слишком много IP.

ВАЖНО: я использую Google Test Framework и функцию main (), которую они предоставляют. В Release я получаю ожидаемое поведение (оператор undef работает и оператор работает). В Debug одно из утверждений препроцессора не получает удар.

test.cpp

#undef ACT_LIKE_HW

#include "gtest/gtest.h"
#include "model.h"

TEST(TestCaseName, TestName) {
    setSignalsFromHW();
    Block::assignSig();
}

hw_model.cpp

#define ACT_LIKE_HW
#include "model.h"

void setSignalsFromHW() {
    Block::assignSig();
}

model.h

#pragma once

#include <iostream>
using namespace std;

void setSignalsFromHW();

class Block {
    public:
        static void assignSig() {
        #ifdef ACT_LIKE_HW
            cout << "Performing hardware operations" << endl;
        #else
            cout << "Procedures that firmware usually executes" << endl;
        #endif
        }
};

Однако, если я создаю совершенно новый проект C ++ (который не использует Google Test, так что это обычное консольное приложение), одно из утверждений препроцессора не попадет ни в Release, ни в Debug, так что это побеждает цель я определяю эти 2 заявления препроцессора. Возможно, я просто закончу рефакторинг кода, но мне все равно хотелось бы знать, почему эта проблема происходит с моим тестовым проектом Google.

1 Ответ

1 голос
/ 18 апреля 2019

У вас нарушение одного правила определения.

Если в программе несколько определений одного и того же символа, ваша программа имеет неопределенное поведение, если оба определения не идентичны.

Обычнодублирующиеся символы удаляются компоновщиком, поэтому только одна из ваших функций выживет, и оба сайта вызовов будут в итоге вызывать одну и ту же функцию.

Если функция встроена компилятором, то код из функции интегрируется ввызывающая функция и компоновщик не будут мешать, поэтому ваш код может работать правильно.Это хрупко, хотя, например, когда в отладке не происходит встраивание или когда ваша функция превышает порог размера компилятора для встраивания, вы вернетесь к тому, чтобы снова иметь только одну функцию.

Чтобы исправить это, передайтелогический параметр для функции, контролирующей, какое поведение вы хотите.Если эта функция встроена, компилятор должен удалить неиспользуемую ветвь кода.

В качестве альтернативы сделать логический параметр параметром шаблона и использовать if constexpr, который будет гарантировать удаление неиспользуемого кода.

...