|
Is it possible to place an expaned macro inside a string literal?
#define NUMBER 123
...
strcmp(SomeString, "NUMBER"); I want the strcmp line to expand to:
strcmp(SomeString, "123"); I need to use the macro as both a string and an integer, and I want to avoid atoi() etc.
I looked at the # and ## preprocessor operators but can not seem to get them to work.
Any ideas greatly appreciated.
Darker than a black steer's tookus on a moonless praire night
Within you lies the power for good, use it!!!
|
|
|
|
|
I got the following from the source of Boost's preprocessor library:
// CommandLine.cpp : Defines the entry point for the console application.
//
#include "StdAfx.h"
#include <iostream>
#define STRINGIZE(text) STRINGIZE_A((text))
#define STRINGIZE_A(arg) STRINGIZE_B ## (arg)
#define STRINGIZE_B(arg) STRINGIZE_I ## arg
#define STRINGIZE_I(text) #text
#define NUMBER Hello
void main()
{
using namespace std;
cout << STRINGIZE(NUMBER) << endl;
}
Steve
|
|
|
|
|
That works, Thanks!
Now I just have to figure out how it works. Looks like black magic to me so far.
It's not rocket surgery!
Within you lies the power for good, use it!!!
|
|
|
|
|
To me it looks like gibberish, a bunch of no-op macro steps.
The intermediate steps just wrap several () around the arg.
Just unroll them to see:
SS(T) == SS_A((T))
SS(T) == SS_B(((T)))
SS(T) == SS_I(((T)))
SS(T) == (((#T)))
You may as well as used SS_I(T) to start with.
I have to believe they use SS_A, SS_B, SS_I elsewhere as part of other macros as well.
[EDIT]
Whoops, just tried it, looks like it does do something.
[/EDIT]
-- modified at 20:02 Monday 30th April, 2007
...cmk
Save the whales - collect the whole set
|
|
|
|
|
An explanation to what Stephen posted.
What would be ideal would be:
#define NUMBER 123
#define ASSTR(X) #X
But, when used in:
strcmp(SomeString, ASSTR(NUMBER));
We get:
strcmp(SomeString, "NUMBER"); because the token is converted _before_ it is checked for further macro expansion.
So we have to remove the expansion by one level (the boost example adds an extra 2 levels for some reason):
#define NUMBER 123
#define STR(X) #X
#define ASSTR(X) STR(X)
Now we get:
strcmp(SomeString, "123");
This is because:
- first ASSTR(NUMBER) is replaced with STR(NUMBER)
- _then_ the macro is checked for further explansion and NUMBER is replaced with 123 _before_ STR() is resolved
- so we get STR(123) which gives "123".
...cmk
Save the whales - collect the whole set
|
|
|
|
|
cmk wrote: (the boost example adds an extra 2 levels for some reason)
Read the article[^] linked by Stephen below. Section A.2.3 explains about how commas and parentheses can screw things up. The Boost code given accounts for this.
Darker than a black steer's tookus on a moonless praire night
Within you lies the power for good, use it!!!
|
|
|
|
|
Ahhh, there had to be a reason - thanks.
...cmk
Save the whales - collect the whole set
|
|
|
|
|
See here[^]. Search for "A.4.4". This might provide some insight as might the rest of the document.
Steve
|
|
|
|
|
Thanks Stephen, great info there!
It's not rocket surgery!
Within you lies the power for good, use it!!!
|
|
|
|
|
Hello,
This is a very basic question for C++ on arrays. I am getting 2 errors when I compile & do not know what I'm doing wrong. Please assist. Lab is due 2 hrs from the time this email is posted, so very soon.
Error is - expected constructor, destructor or type conversion before = token
and - expected , or ; before = token
void pause(void);
void load_array_from_file(fileSpec filename, arrayType nums, int arraySize);
void display_array(arrayType nums, int arraySize);
int sum_array(arrayType nums, int arraySize);
int average_array;
(lots of other coding in here)
average_array = total / sum_array;
Thanks for the help!
Melissa
|
|
|
|
|
wertyou wrote: average_array = total / sum_array;
what type is total ?
Why are you calling sum_array without any parameters?
It's not rocket surgery!
Within you lies the power for good, use it!!!
|
|
|
|
|
Ok- here is the whole lab & the compiler errors are on line 127, which is the average_array. The total is defined in the sum part.
#include<iostream>
#include<string>
#include <iomanip> // For setw()
#include <fstream> // For file I/O
#include <cstdlib> // For the exit() function
using namespace std;
typedef int arrayType[]; // Declare data type alias
typedef char fileSpec[]; // Declare data type alias
// user defined function prototypes
void pause(void);
void load_array_from_file(fileSpec filename, arrayType nums, int arraySize);
void display_array(arrayType nums, int arraySize);
int sum_array(arrayType nums, int arraySize);
int average_array;
//******************************************************
// main
//******************************************************
int main(void)
{
//------------------------------------------------------
// Place the D6_Lab_01_Input.txt file on the root level
// of your C: (hard disk) drive
//------------------------------------------------------
char filename[] = "c:\\D6_Lab_01_Input.txt";
const int FARMERS = 7; // Input file has at least 7 members
int acres[FARMERS];
// call functions
load_array_from_file(filename, acres, FARMERS);
cout << "The individual farm acerages are: \n";
display_array(acres, FARMERS);
cout << "\n\nThe total acerage is: " << sum_array(acres, FARMERS);
cout << "\n\nThe average acerage is: " << average_array;
pause();
return 0;
}
//******************************************************
// pause
//******************************************************
void pause(void)
{
char pause;
cout << "\n\n\nHit Enter Key to Continue: ";
cin.get(pause);
cin.get(pause);
return;
}
//******************************************************
// load_array_from_file
//******************************************************
void load_array_from_file(fileSpec filename, arrayType nums, int arraySize)
{
ifstream inData; // Used to read the data from a file
int index; // Loop counter
inData.open(filename); //Open input file
if (!inData)
{
cout << "\n\nError opening data file: " << filename << "\n\n";
pause();
exit(EXIT_FAILURE);
}
else
{
for (index = 0; index < arraySize; index++) // Load the array
{
inData >> nums[index];
}
inData.close();
}
return;
}
//******************************************************
// display_array
//******************************************************
void display_array(arrayType nums, int arraySize)
{
int index; // Loop counter
cout << "\n*************************";
for (index = 0; index < arraySize; index++)
{
cout << "\nMemeber " << index+1 << " value is: " << setw(5) << nums[index];
}
cout << "\n*************************";
return;
}
//******************************************************
// sum_array
//******************************************************
int sum_array(arrayType nums, int arraySize)
{
int index; // Loop counter
int total = 0; // Accumulator
for (index = 0; index < arraySize; index++)
{
total += nums[index];
}
return total;
}
//******************************************************
// average_array
//******************************************************
average_array = total / sum_array;
//******************************************************
// End of Program
//******************************************************
Mel
|
|
|
|
|
Ok, you posted a pile of code but your last lne makes no sense. Is average_array supposed to be a function? If it is a variable how are you setting it? That last line of code is not inside any function so it will not work as is. Also, you declared sum_array to be a function that takes two parameters, but in the last line you are treating it as a variable, that will not work.
Straighten out what you want that last line to be.
Darker than a black steer's tookus on a moonless praire night
Within you lies the power for good, use it!!!
|
|
|
|
|
Thanks a lot - I put the last line in the for of the sum function above and changed the operand to match the variable.
It works now- great!
Thanks again,
Melissa
|
|
|
|
|
hi
i want to find the temp folder path of the user and not the windows.
so is there a way to get the info.
thnx
|
|
|
|
|
Look up SHGetSpecialFolderPath(). You're looking for a CSIDL that matches the folder you're trying to get - the closest I could find was CSIDL_INTERNET_CACHE which is for storing the user's temporary internet files.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
well this is ok but i think we don't have direct way to do that.
do we have?
well this leads to C:\WINDOWS\TEMP when i want something C:\Documents and Settings\User\Local Settings\Temp.
any idea??
|
|
|
|
|
I gave you the function name...
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
yap
thanks a lot for the help.
|
|
|
|
|
In the "old days" the "TEMP" or "TMP" environment variable was used.
The GetTempPath() API will get you that path.
For new apps, I highly recommend following the OS guidelines for storing application data.
It can save a lot of headaches in the newer, more secure, OSs (ie Vista).
The best document I've found for this is the XP logo specs, section 3 (more specifically, 3.2).
Here's an excerpt:
From "Designed for Microsoft Windows XP” Application Specification
This section identifies the valid file folders and the valid registry locations that applications
must use for this data, and gives guidance on how to choose which of these locations are best
used in different circumstances. The choice of valid locations to use is left to the software
developer.
Classify application data into the following categories:
• Per user, roaming
• Per user, non-roaming
• Per computer (non-user specific and non-roaming)
NOTE There may be more than one category for the different application data stored by your
application.
For applications not intended to be used in a domain environment (most games and home products
for example), classifying the application data as per user, non-roaming might be an appropriate
choice.
It is best to use application data file folders rather than the registry for storing application
data in excess of 64K. The registry is an acceptable choice for small amounts of data. At
installation time, try to store less than a total of 128K across HKEY_CURRENT_USER (HKCU) and
HKEY_LOCAL_MACHINE (HKLM).
To comply with this specification, store application data files appropriately as either common or
per-user. That is:
• In a subfolder of either the common application folder (identified by
CSIDL_COMMON_APPDATA), or
• In the user profile folders: application data (CSIDL_APPDATA) or local application data
(CSIDL_LOCAL_APPDATA).
The subfolder to create to store user data files in is:
[company name]\[product name]\[version].
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
thnx for the info. i'll go through it to see what i am not doing.
|
|
|
|
|
near2world wrote: well this leads to C:\WINDOWS\TEMP when i want something C:\Documents and Settings\User\Local Settings\Temp.
any idea??
Then you probably need to set the environment variables properly.
Mine look like this on XP:
TEMP = %USERPROFILE%\Local Settings\Temp
TMP = %USERPROFILE%\Local Settings\Temp
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
|
near2world wrote: i want to find the temp folder path of the user and not the windows.
Another option is to use environment variable %temp% .
|
|
|
|
|
well this leads to C:\WINDOWS\TEMP when i want something C:\Documents and Settings\User\Local Settings\Temp.
any idea??
|
|
|
|