Problem with MACros

Problem with Macros

Neil Butterworth, Mark and Pavel are right.

SQUARE(++y) expands to ++y * ++y, which increments twice the value of y.

Another problem you could encounter: SQUARE(a + b) expands to a + b * a + b which is not (a+b)*(a+b) but a + (b * a) + b. You should take care of adding parentheses around elements when needed while defining macros: #define SQUARE(X) ((X) * (X)) is a bit less risky. (Ian Kemp wrote it first in his comment)

You could instead use an inline template function (no less efficient at runtime) like this one:

template <class T>
inline T square(T value)
{
return value*value;
}

You can check it works:

int i = 2;
std::cout << square(++i) << " should be 9" << std::endl;
std::cout << square(++i) << " should be 16" << std::endl;

(no need to write

square<int>(++i)

because the int type is implicit for i)

Trouble with excel macros (possibly encoding?)

Easiest workaround way is to rename them and not use any odd characters besides english ones. Any other characters can cause issues depending on the region settings of the computer using it.

So if using different region settings on different computers: Do not use foreign characters in your VBA editor, or you can run into such issues.

To solve your issue:

  • Replace your macro names with english ones to ensure they work in every region world wide
  • or check your region settings and ensure every computer uses the same settings and same codepage

Also see How To Display Foreign Characters In Excel VBE

How to solve the problem in excel: Macros are disabled

Try on File tab -> Option -> Trust Center ->Trust Center Settings -> Macro Settings -> Enable all Macros

What problems might the following macro bring to the application?

Yes, it can present problems. Other than the obvious fact that macros don't respect namespaces at all (which means you can't call anything else sq), try the following:

int result = sq(4) / sq(4);

You should surround x * x with parenthesis so it becomes ((x) * (x)).

Another problem:

int a = 0;
int result = sq(++a);

This is an inherent problem with macros, and is one reason inline functions should be preferred.

Issues with macros and formulas in Excel

Please refer to the answer by Monster for the correct solution to the problem.

I have to leave this answer here until it is "unaccepted", and then I will be able to delete it.


To enter locale-dependent formulas, you need to use FormulaLocal:

Cells(LastRow + 1, 3).FormulaLocal = "=SI.ERROR(BUSCARV(B" & laststr & " , Datos!A2:E52, 3), """")"

Excel VBA Macro called from VB IDE works fine, but fails when called from a button until file is saved multiple times

After much troubleshooting, I think I finally found the cause of this dilemma. It dawned on me that the stupid thing was crashing more and more and more, so, I did what any reasonable person would - copied all the sheets over to a brand new xlsm book. Then, I copied the text of the VBA Modules into a separate Text editor, and recreated them all. All the forms I had were safe (THANKFULLY) so exporting those and importing them to the new one was simple enough to do.

A major pitfall to be aware of: there was a warning about links to other files - turns out it had kept links to the old document in the BUTTONS (of all things)!! I used Edit Links under the Data Ribbon menu (grayed out now because they're all gone! WOOT!

Everything seems to be working fine now!

I have to give this StackOverflow article (and subsequently allula at Ozgrid as well even though the linked article there is broken) some major Kudos. This is what led me to this solution to begin with. I'll be cross commenting on the linked post about my experience too in case nobody finds this one.

Additionally, as an added protection measure, I made the path of the workbook a trusted path and provided a subroutine to give the intended users this option without having to do it manually, only doing so when they accept it and removing it if they move the file and select "no" on the same request prompt.

Why are preprocessor macros evil and what are the alternatives?

Macros are just like any other tool - a hammer used in a murder is not evil because it's a hammer. It is evil in the way the person uses it in that way. If you want to hammer in nails, a hammer is a perfect tool.

There are a few aspects to macros that make them "bad" (I'll expand on each later, and suggest alternatives):

  1. You can not debug macros.
  2. Macro expansion can lead to strange side effects.
  3. Macros have no "namespace", so if you have a macro that clashes with a name used elsewhere, you get macro replacements where you didn't want it, and this usually leads to strange error messages.
  4. Macros may affect things you don't realize.

So let's expand a little here:

1) Macros can't be debugged.
When you have a macro that translates to a number or a string, the source code will have the macro name, and many debuggers can't "see" what the macro translates to. So you don't actually know what is going on.

Replacement: Use enum or const T

For "function-like" macros, because the debugger works on a "per source line where you are" level, your macro will act like a single statement, no matter if it's one statement or a hundred. Makes it hard to figure out what is going on.

Replacement: Use functions - inline if it needs to be "fast" (but beware that too much inline is not a good thing)

2) Macro expansions can have strange side effects.

The famous one is #define SQUARE(x) ((x) * (x)) and the use x2 = SQUARE(x++). That leads to x2 = (x++) * (x++);, which, even if it was valid code [1], would almost certainly not be what the programmer wanted. If it was a function, it would be fine to do x++, and x would only increment once.

Another example is "if else" in macros, say we have this:

#define safe_divide(res, x, y)   if (y != 0) res = x/y;

and then

if (something) safe_divide(b, a, x);
else printf("Something is not set...");

It actually becomes completely the wrong thing....

Replacement: real functions.

3) Macros have no namespace

If we have a macro:

#define begin() x = 0

and we have some code in C++ that uses begin:

std::vector<int> v;

... stuff is loaded into v ...

for (std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it)
std::cout << ' ' << *it;

Now, what error message do you think you get, and where do you look for an error [assuming you have completely forgotten - or didn't even know about - the begin macro that lives in some header file that someone else wrote? [and even more fun if you included that macro before the include - you'd be drowning in strange errors that makes absolutely no sense when you look at the code itself.

Replacement: Well there isn't so much as a replacement as a "rule" - only use uppercase names for macros, and never use all uppercase names for other things.

4) Macros have effects you don't realize

Take this function:

#define begin() x = 0
#define end() x = 17
... a few thousand lines of stuff here ...
void dostuff()
{
int x = 7;

begin();

... more code using x ...

printf("x=%d\n", x);

end();

}

Now, without looking at the macro, you would think that begin is a function, which shouldn't affect x.

This sort of thing, and I've seen much more complex examples, can REALLY mess up your day!

Replacement: Either don't use a macro to set x, or pass x in as an argument.

There are times when using macros is definitely beneficial. One example is to wrap a function with macros to pass on file/line information:

#define malloc(x) my_debug_malloc(x, __FILE__, __LINE__)
#define free(x) my_debug_free(x, __FILE__, __LINE__)

Now we can use my_debug_malloc as the regular malloc in the code, but it has extra arguments, so when it comes to the end and we scan the "which memory elements hasn't been freed", we can print where the allocation was made so the programmer can track down the leak.

[1] It is undefined behaviour to update one variable more than once "in a sequence point". A sequence point is not exactly the same as a statement, but for most intents and purposes, that's what we should consider it as. So doing x++ * x++ will update x twice, which is undefined and will probably lead to different values on different systems, and different outcome value in x as well.



Related Topics



Leave a reply



Submit