0

I recently learned of the ## functionality that i can define in the beginning of my code. I'm trying to compile the following code:

#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <stdio.h>
#include <string>

#define paste(x,y) *x##*y

int main()
{

TCHAR *pcCommPort = "COM";
TCHAR *num = "5";

cout << paste(pcCommPort,num);
return 0;
}

and i keep getting the following error:

expression must have arithmetic or unscoped enum type

it's not liking the fact that i'm using pointers in my "define paste" line. Without any pointers, it'll just return the variable "pcCommPort5." what I want is "COM5."

I've tried _tcscat, strcat, strcat_s, visual studio didn't like any of these....

Ben Marconi
  • 161
  • 1
  • 1
  • 7
  • Don't use the preprocessor if you don't have to. It executes before normal compilation (as hinted by its name), not at runtime. – chris Jan 11 '16 at 03:06
  • `_tcscat` should work, you just need to provide a writeable buffer of the proper size. Create a third variable as an array of `TCHAR`, use `_tcscpy` to copy the first string into it, then use `_tcscat` to add the second string. Or use `std::basic_string` instead and save yourself a lot of grief. Or forget about `TCHAR` entirely, since you'll probably never use it configured as `char`, and use `std::wstring`. – Mark Ransom Jan 11 '16 at 03:06
  • Oops, never mind that last part of my comment, since you're successfully assigning a normal `char` string to the variable you must be configured so `TCHAR` is `char`. That means you should use `std::string`. – Mark Ransom Jan 11 '16 at 03:10
  • 1
    `#include ` You included this header, but failed to use any functionality defined in it. – PaulMcKenzie Jan 11 '16 at 03:12
  • If you're programming in C++, just use stringstream and be done with it. – MrEricSir Jan 11 '16 at 03:36

1 Answers1

1

## doesn't concatenate arbitrary things (especially not strings). What it does it is merges symbols together in the parser into a single symbol.

Let's remove one of those * to see what's going on:

#include <iostream>

#define TO_STRING_HELPER(x) #x
#define TO_STRING(x) TO_STRING_HELPER(x)
#define CONCAT(x, y) *x##y

int main() {
    char *pcCommPort = "COM";
    char *num = "5";
    std::cout << TO_STRING(CONCAT(pcCommPort, num)) << std::endl;
}

Output:

*pcCommPortnum

What CONCAT does in this code is:

  1. Expand x into pcCommPort and y into num. This gives the expression *pcCommPort##num.
  2. Concatenate the two symbols pcCommPort and num into one new symbol: pcCommPortnum. Now the expression is *pcCommPortnum (remember, that last part (pcCommPortnum) is all one symbol).
  3. Finish evaluating the full macro as a * followed by the symbol pcCommPortnum. This becomes the expression *pcCommPortnum. Remember, those are two different symbols: * and pcCommPortnum. The two symbols just follow one after the other.

If we were to try to use *x##*y, what the compiler does is this:

  1. Expand x into pcCommPort and y into num. This gives us the expression *pcCommPort##*num.
  2. Concatenate the two symbols pcCommPort and * into one new symbol: pcCommPort*.
  3. Here, the preprocessor hits an error: the single symbol pcCommPort* is not a valid preprocessing token. Remember, it's not two separate symbols at this point (it is not two symbols pcCommPort followed by *). It is one single symbol (which we call a token).

If you want to concatenate two strings, you're way better off using std::string. You can't* do what you're trying to do with the preprocessor.

*Note, though, that consecutive string literals will be merged together by the compiler (i.e. "COM" "5" will be merged into a single string "COM5" by the compiler). But this only works with string literals, so you'd have to #define pcCommPort "COM" and #define num "5", at which point you could do pcCommPort num (without any further macros) and the compiler would evaluate it to the string "COM5". But unless you really know what you're doing, you really should just use std::string.

Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • That doesn't work. Just try `#define paste pcCommPort num` – Barmak Shemirani Jan 11 '16 at 03:19
  • @BarmakShemirani: What do you mean "that doesn't work"? Of course it doesn't work. It's impossible to do what the OP wants with macros. Also, your suggestion doesn't work. – Cornstalks Jan 11 '16 at 03:20
  • Oh, sorry I thought `pcCommPort` and `num` were predefined macros – Barmak Shemirani Jan 11 '16 at 03:21
  • Cornstalks, clarification much appreciated! ||| MrEricSir, how might I go about using stringstream library? ||| Mark Ransom, I 've gotten as far as concatenating type TCHARs with string like such: TCHAR *A = "COM"; TCHAR *B = "5"; string C = A + B; this does work. But I need to convert this back to a type TCHAR which I haven't had any luck with :( ||| Regarding your previous suggestion using wstring, tscpy, and tcscat, i think I might need a step by step instruction for these, i've been meddling with those functions for quite a while noW >, – Ben Marconi Jan 11 '16 at 12:19
  • @BenMarconi: You can do `std::string a = "COM";` and `std::string b = "5";` and `std::string c = a + b;`. If you need a `char*`, you can call [`c.c_str()`](http://en.cppreference.com/w/cpp/string/basic_string/c_str). If you want to use a `std::stringstream`, [this demo may help](http://en.cppreference.com/w/cpp/io/basic_stringstream/str). – Cornstalks Jan 11 '16 at 15:49