I have the following code:
#define MY_MACRO(PARAM) int PARAM_int; double PARAM_double; [subsequent instructions]
Unfortunately, it does not work, meaning that PARAM is not replaced inside the variables names. Is this solvable some way?
PARAM_int is considered to be a single token, that is distinct from PARAM. You can concatenate tokens in a macro definition with ##:
#define MY_MACRO(PARAM) int PARAM ## _int; double PARAM ## _double;
Now, PARAM will expand to whatever you invoke the macro with, and then the resulting token will be pasted together with _int and _double.
Related
I need to build my code with a variable MyVar. I need to build it eg. 10 times but for each time, MyVar would be different, eg.
First build:
static unsigned char MyVar[] = "ABC";
Second build:
static unsigned char MyVar[] = "XYZ";
Is there an option to do this in a batch style? Eg. the command line? I just don't want to change MyVar manually, press "build", rename the built file etc.
Thanks a lot
PS: I'm not a professional coder, this could be bad practice. At the same time I'd just like to get the job done and don't want to change the code too much.
PPS: Already looked into several things (property sheets, custom macros, per-/post build actions, environment variables) but didn't find anything suitable.
Here is a sample C++ program utilizing a macro named MY_MACRO that you'll set in the CL environment variable using the /D option, before invoking MSBuild:
#include <iostream>
#include <string>
#ifndef MY_MACRO
#define MY_MACRO "unknown"
#endif
std::string greeting(const std::string& their_name)
{
static constexpr char my_name[] = MY_MACRO;
return "Hello, " + their_name + ", nice to meet you!\nMy name is " + my_name + '.';
}
int main()
{
std::cout << "Please enter your name: ";
std::string their_name;
std::cin >> their_name;
std::cout << greeting(their_name) << '\n';
}
As described in the docs mentioned above, when dealing with environment variables, you'll use the number sign (#) instead of the equal sign (=) to define a preprocessor constant with an explicit value. Also, the double-quotes (") need to be escaped (like \") when defining a string constant via command line.
To sum it up, here is a sample PowerShell script to build and collect ten different executables, each of which will be using a different string literal for the value of MY_MACRO, selected from a list of names, in a loop (note that in the script, \" needs to be expressed as \`" using a backtick before double-quotes, so that PowerShell will interpret literally those double-quotes inside a double-quoted string):
$MSBuildExe = 'C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe'
$MSBuildCmdLineArgs = #('MySolution.sln', '/property:Configuration=Release;Platform=x64', '/target:Rebuild', '/maxCpuCount')
New-Item -Force -ItemType Directory -Name 'CollectedExecutables'
$Names = #('Anni', 'Frida', 'Kadi', 'Mari', 'Piia', 'Pille', 'Piret', 'Reet', 'Siret', 'Triinu')
foreach ($MyNameString in $Names)
{
$env:CL = "/DMY_MACRO#\`"$MyNameString\`""
& $MSBuildExe $MSBuildCmdLineArgs "/property:TargetName=executable_named_$MyNameString"
Copy-Item -LiteralPath "x64\Release\executable_named_${MyNameString}.exe" -Destination 'CollectedExecutables'
}
In this script, I'm assuming you're using Visual Studio 2022; otherwise just change the value of $MSBuildExe to the appropriate path. Also, I'm assuming you want to build a Release (not Debug) configuration of your C++ project, and that you want to build for the x64 platform. If not, change those strings in the script accordingly. And of course, put the actual name of your C++ solution file (instead of MySolution.sln) into the first element of the MSBuild command-line arguments array in the script.
Please explain "keyword arguments" and give some examples of their use.
A function may use positional arguments and/or keyword arguments. Function arguments are used to provide functions with values developed outside of the function itself, values the function needs to know. For a given function, the actual value assigned to a specific argument may change from one call to the next.
A positional argument holds the place for specified value by its ordinal position in the function's argument list. For example, x and real, imag are positional arguments in these function definitions:
sqrt(x) = x^0.5
complex(real, imag) = real + imag*im
A keyword argument holds the place of a specified value by its name. The last (rightmost) positional argument comes before the first keyword argument. A semicolon (;) demarks the start of keyword arguments, even when there are no positional arguments. When both kinds of argurment are used, the semicolon separates the positional from the keyword arguments. For example, digitcount and digits are keyword arguments in this function definition:
roundedstring(x; digitcount) = string(round(x, digits=digitcount))
Here is an example that only uses keyword arguments:
function pathname(; dirpath, filename)
return joinpath(dirpath, filename)
end
dir_path = "/home/workfiles"
file_name = "current.txt"
path_name = pathname(dirpath=dir_path, filename=file_name)
# pathname == "/home/workfiles/current.txt"
Here is almost the same example, using both kinds of argument:
function pathname(dirpath; filename)
return joinpath(dirpath, filename)
end
dir_path = "/home/workfiles"
file_name = "current.txt"
path_name = pathname(dir_path, filename=file_name)
# pathname == "/home/workfiles/current.txt"
One reason to use keyword arguments:
function copyfile(; source, dest)
# function body
end
src_pathname = "~/current.txt"
dst_pathname = "/home/workfiles/current.txt"
# now both of these work
copyfile(source = src_pathname, dest = dst_pathname)
copyfile(dest = dst_pathname, source = src_pathname)
Using a keyword argument to allow changing a default setting:
function translate(text; language="en")
# translation function body
end
Using a keyword argument to require something:
#=
If the keyword `language` is not specified
when calling this function, a error occurs.
=#
function translate(text; language)
# translation function body
end
Both kinds of argument may have default values to use when an argument is omitted in a function call. All positional arguments that do not specify a default value must preceed all positional arguments that do specify default values. Keyword arguments have the same requirement, any with a default value must follow all keyword arguments that do not specify a default value.
Please see the docs for more information on keyword arguments and optional keyword arguments.
I've found what seems to be an incompatibility between using C-style macros and using the new unified list-initialization form introduced in C++11, but it seems incredible that this sort of thing would be absolutely impossible to write, so I assume I'm missing something.
Here's the issue: curly brackets seem to be ignored when the preprocessor looks to find a macros arguments. A call like MACR(Range{2,4}) is misinterpreted as having two arguments, Range{2 and 4. In the following code, it's all good (well, poor style, but it works) until the marked line:
#include <iostream>
using namespace std;
struct Range { int st, fn; };
ostream& operator << (ostream& out, const Range& r)
{ return out << "(" << r.st << "," << r.fn << ")"; }
#define COUT(X) (cout << (X) << endl)
int main()
{
COUT(3);
Range r {3,5};
COUT(r);
COUT(Range{3,5}); //this line won't compile
}
It gives the following error message:
badmacro.cpp:16:18: error: macro "COUT" passed 2 arguments, but takes just 1
COUT(Range{3,5});
^
compilation terminated due to -Wfatal-errors.
Especially when working with older libraries, it's sometimes unavoidable to use macro calls; surely we're not supposed to forgo the new syntax in those cases? Is there an official workaround for this?
If you need to pass an expression to an existing macro, and an expression contains unshielded commas, just enclose the whole expression in parentheses.
COUT((Range{3,5}));
Ugly? Yes, but that's what happens when you are using macros. Don't do that.
If it's not an expression and can't take extra parentheses, then you simply can't use that macro.
If you are writing a macro, which you shouldn't, sometimes you can write a variadic macro (if your compiler supports that):
#define COUT(...) cout << (__VA_ARGS__) << endl;
Preprocessor macros are just fancy text replacements prior to compiling. When calling a macro, the preprocessor does very little parsing of the parameter list. There is some logic to differentiate between commas inside of nested parenthesis versus outside, so it knows which commas belong to the parameter list of the macro itself versus commas for the parameter list of a nested function call. For example:
macro(param1, param2, func(param1, param2) )
The parameters are interpreted as
param1
param2
func(param1, param2)
Rather than
param1
param2
func(param1
param2)
In your case, your comma is not inside of nested parenthesis, so the preprocessor ends up splitting the parameter list Range{3,5} into two parameter values
Range{3
5}
Hence the error because your macro only accepts one parameter. The preprocessor does not have any context information to know that Range{3,5} should be treated as one parameter value. It just sees the comma and splits on it.
So, to solve your problem, try adding an extra pair of parenthesis:
COUT((Range{3,5}));
The preprocessor should then interpret one parameter value:
(Range{3,5})
Which will create the following statement for the compiler to consume:
(cout << ((Range{3,5})) << endl);
I need to actually print a Dollar sign in Dart, ahead of a variable. For example:
void main()
{
int dollars=42;
print("I have $dollars."); // I have 42.
}
I want the output to be: I have $42. How can I do this? Thanks.
Dart strings can be either raw or ... not raw (normal? cooked? interpreted? There isn't a formal name). I'll go with "interpreted" here, because it describes the problem you have.
In a raw string, "$" and "\" mean nothing special, they are just characters like any other.
In an interpreted string, "$" starts an interpolation and "\" starts an escape.
Since you want the interpolation for "$dollars", you can't use "$" literally, so you need to escape it:
int dollars = 42;
print("I have \$$dollars.");
If you don't want to use an escape, you can combine the string from raw and interpreted parts:
int dollars = 42;
print(r"I have $" "$dollars.");
Two adjacent string literals are combined into one string, even if they are different types of string.
You can use a backslash to escape:
int dollars=42;
print("I have \$$dollars."); // I have $42.
When you are using literals instead of variables you can also use raw strings:
print(r"I have $42."); // I have $42.
We have a piece of cross-platform code that uses wide strings. All our string constants are wide strings and we need to use CFSTR() on some of them. We use these macros to get rid of L from wide strings:
// strip leading L"..." from wide string macros
// expand macro, e.g. turn WIDE_STRING (#define WIDE_STRING L"...") into L"..."
# define WIDE2NARROW(WideMacro) REMOVE_L(WideMacro)
// L"..." -> REM_L"..."
# define REMOVE_L(WideString) REM_##WideString
// REM_L"..." -> "..."
# define REM_L
This works on both Windows and Linux. Not on Mac – we get the following error:
“error: pasting "REM_" and "L"qm"" does not give a valid preprocessing token”
Mac example:
#define TRANSLATIONS_DIR_BASE_NAME L"Translations"
#define TRANSLATIONS_FILE_NAME_EXTENSION L"qm"
CFURLRef appUrlRef = CFBundleCopyResourceURL( CFBundleGetMainBundle()
, macTranslationFileName
, CFSTR(WIDE2NARROW(TRANSLATIONS_FILE_NAME_EXTENSION))
, CFSTR(WIDE2NARROW(TRANSLATIONS_DIR_BASE_NAME))
);
Any ideas?
During tokenization, which happens before the preprocessor language, string literals are processed. So the L"qm" is converted to a wide string literal. Which means you are trying to token paste with a string literal(and not the letter L), which C99 forbids.