Help me making a small change in a C++ program

21 risposte [Ultimo contenuto]
mYself
Offline
Iscritto: 01/18/2012

Read here:

http://stackoverflow.com/questions/33220415/modifying-virtualbox-gui-to-use-kchmviewer-if-available

There are two mistakes in the provided link that I'm currently aware of:

1. I cannot use #define in my statement, however, I'm somewhat confused about which (int, const, float, QString, QList, etc.) combination of variable/data type should I choose, and why.
2. Instead of setting USE_KCHMVIEWER to "0", I actually have to undefine it (how?).

I would be grateful if someone could help fix the code, and pointed to the file/location where it should be placed.

Thanks in advance.

Peter

onpon4
Offline
Iscritto: 05/30/2012

What you're trying to do isn't possible. #define is a preprocessor command, executed at compile time. Any instances of USE_KCHMVIEWER get replaced in the code, before it is compiled, with the value of USE_KCHMVIEWER. So there isn't a way to change such constants at run-time, and "undefining" them doesn't make any sense.

What you need to do is modify the code to remove USE_KCHMVIEWER from the relevant decision(s). Probably, it should be removed entirely and replaced with a variable. I'm not familiar with VirtualBox, so I don't know how difficult this is. But the type you would want to use is bool.

mYself
Offline
Iscritto: 01/18/2012

So, you're telling me that C++, a powerful programming language that's powering operating systems and state-of-the-art games, isn't powerful enough to define a simple conditional statement? Even a shell script (dash) can do this:

#!/bin/sh

which kchmviewer > /dev/null

if [ $? = 0 ]
then	# "which kchmviewer" exit code 0
	USE_KCHMVIEWER=1
else	# "which kchmviewer" exit code 1
	USE_KCHMVIEWER=
fi

if [ "$USE_KCHMVIEWER" = '' ]
then
	echo kchmviewer IS NOT installed.
else
	echo kchmviewer IS installed.
fi

USE_KCHMVIEWER is not used in the code, however, I would like to replace VBOX_OSE with it in the mentioned cases.

What do you mean by that USE_KCHMVIEWER isn't a variable? I understand that VBOX_OSE (some of whose occurrences I want to replace with USE_KCHMVIEWER) is a compile-time option. Now, I just want to create a code that could define this at run-time instead of compile-time, and then put it somewhere into the codebase. The expected result should be that whenever I access the documentation inside the GUI, either the CHM or PDF file will be opened based on what document viewer is available at the moment (kind of a OSE/non-OSE hybrid*).

So you're basically saying that variables (or whatever USE_KCHMVIEWER is) used in preprocessor statements (the lines with a hashtag) cannot be changed/redefined once the program is compiled because they are replaced by their value (i.e. they are hardcoded). What would be the preferred way to work around this (i.e. what should I use instead of # ifdef USE_KCHMVIEWER, and # if !defined USE_KCHMVIEWER)?

* https://forums.virtualbox.org/viewtopic.php?f=10&t=73979#p342127

quantumgravity
Offline
Iscritto: 04/22/2013

He's telling you that this is of course possible if USE_KCHMVIEWER is a variable, but at the moment, it's not.
The compiler won't no about USE_KCHMVIEWER at all, because before it starts to compile, the so called "preprocessor" already replaced every single chain of characters that are "USE_KCHMVIEWER" with whatever you have defined in #define.
if you defined it to be "3", then the compiler will just find "3" in the source code.

int USE_KCHMVIEWER
becomes (after preprocessing and BEFORE compiling)
int 3

that's what the compiler gets.

mYself
Offline
Iscritto: 01/18/2012

I understood that part, I just don't understand C++ yet. The main problem is that I'm unable to test the changed code before the compilation, only after. Together this means that it's very difficult for me to work on the code.

onpon4
Offline
Iscritto: 05/30/2012

> So, you're telling me that C++, a powerful programming language that's powering operating systems and state-of-the-art games, isn't powerful enough to define a simple conditional statement?

No, I'm telling you that C++ is a compiled language, and #define (and other statements starting with a hash) is not even C++ code, but a C++ preprocessor directive which is executed at compile-time. It's simply not possible to use code executed at compile-time to do something at run-time.

> What do you mean by that USE_KCHMVIEWER isn't a variable?

It's a preprocessor-defined constant. This is not the same as a variable, and as I said, it's not technically possible to change it after the program has been compiled.

For example, if you have this:

#define FOO ((5 + 3) / 2)

Then the preprocessor goes through all the relevant C++ code before compiling and replaces all instances of "FOO" with "((5 + 3) / 2)". So for example, this:

int x = FOO;

becomes this:

int x = ((5 + 3) / 2);

So a compiled binary never sees that "FOO" constant. It only sees "((5 + 3) / 2)".

> What would be the preferred way to work around this (i.e. what should I use instead of # ifdef USE_KCHMVIEWER, and # if !defined USE_KCHMVIEWER)?

As I said, use variables. (Or, depending on the specifics, a constant defined with the const keyword). It needs to be all based on C++ code, not preprocessor directives, because preprocessor directives are all handled at compile-time.

mYself
Offline
Iscritto: 01/18/2012

Thank you. I'm going to use this information to make some tests and will report back once I get something useful.

mYself
Offline
Iscritto: 01/18/2012

I replaced #define with bool as suggested (note: why this doesn't work?)

if (system("which kchmviewer > /dev/null") == 0)
{
    // "which kchmviewer" exit code 0
    bool useKchmviewer = true;
}
else
{
    // "which kchmviewer" exit code 1
    bool useKchmviewer = false;
}

but the compilation was terminated with the following message (screenshot):

warning: unused variable ‘useKchmviewer’ [-Wunused-variable]

Based on what I read on the Internet (I need to declare a variable first, then I can change the value later), I tried a different approach (note: while this seems to work, I would also like to know how to do this, if possible, using an if…else statement as pointed out above):

bool useKchmviewer = false;

if (system("which kchmviewer > /dev/null") == 0)
{
    // "which kchmviewer" exit code 0
    useKchmviewer = true;
}

This worked, however once I tried to use this with

if (!useKchmviewer)
{
    const QString name = "UserManual";
    const QString suffix = "pdf";
}
else
{
    const QString name = "VirtualBox";
    const QString suffix = "chm";
}

the compiler was unhappy again (screenshot). Based on the answer from Stack Overflow, I altered this code too (note: why is this necessary?):

QString name = "UserManual";
QString suffix = "pdf";

if (useKchmviewer)
{
    name = "VirtualBox";
    suffix = "chm";
}

After this, the compilation finished successfully and the changes worked as expected. However, I still need to adapt other parts of the code so this is only a partial success.

P.S.: I understand how frustrating can be to help a person that doesn't have any knowledge in the topic he/she's expecting to get help in, but please bear with me.

Magic Banana

I am a member!

I am a translator!

Offline
Iscritto: 07/24/2010

warning: unused variable ‘useKchmviewer’ [-Wunused-variable]

That is not an error. Only a warning. The code was compiling successfully. The warning is telling you that the Boolean you defined is not used: you write in the variable "useKchmviewer" but never read from it.

mYself
Offline
Iscritto: 01/18/2012

I only mentioned the relevant message there (see the attached screenshot above). The problem is with the code that's following right after, that sets the variables for the filename of the document file, that will be opened by the frontend. If those variables aren't set, the compilation terminates with an error.

mYself
Offline
Iscritto: 01/18/2012

Finally, I'm in the stage where my changes are working properly. There's one important thing left to do before they will be usable. I would like to know where should I place

bool useKchmviewer = false;

if (system("which kchmviewer > /dev/null") == 0)
{
    // "which kchmviewer" exit code 0
    useKchmviewer = true;
}

in the program codebase so I can check for variable useKchmviewer from wherever I want, specifically VirtualBox-5.0.6/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp and VBoxGlobal.cpp. How can I do this?

lembas
Offline
Iscritto: 05/13/2010

Virtualbox is non-free since 4.2. :-/

However there are alternatives.

mYself
Offline
Iscritto: 01/18/2012

VirtualBox is under GPLv2 besides the Extension Pack, which is under PUEL. The main problem with it is that some parts require non-free compilers, tools, and operating systems to be built. I'm not using these parts so this doesn't affect me.

lembas
Offline
Iscritto: 05/13/2010

You're not using the BIOS?

mYself
Offline
Iscritto: 01/18/2012

I'm using the older code from before the developers rewrote it for Open Watcom. However, the BIOS is only one of the several freedom issues that VirtualBox currently has.

lembas
Offline
Iscritto: 05/13/2010

One is enough but please enlighten me!

mYself
Offline
Iscritto: 01/18/2012

While I'm sure you (and other people here) are interested to know the details, I decided that I would rather not initiate a discussion about this until the time comes. Hopefully, it will be soon.

Magic Banana

I am a member!

I am a translator!

Offline
Iscritto: 07/24/2010

Just a simplification:
bool useKchmviewer = system("which kchmviewer > /dev/null") == 0;

mYself
Offline
Iscritto: 01/18/2012

Thanks, this'll sure come handy. I'm gonna test it right away.

On the subject, do you also know how to redirect the output of "which kchmviewer" to /dev/null if called through QProcess::execute() instead of system()? I recieved a suggestion on Stack Overflow to use it instead, but this doesn't seem to work:

if (QProcess::execute("which kchmviewer > /dev/null") == 0)
…

Thanks in advance.

Magic Banana

I am a member!

I am a translator!

Offline
Iscritto: 07/24/2010

I do not know.

mYself
Offline
Iscritto: 01/18/2012

OK. (sorry for the delay)

mYself
Offline
Iscritto: 01/18/2012

Works like a charm. Thanks!