What is the difference between _tmain() and main() in C++? - c++

If I run my C++ application with the following main() method everything is OK:
int main(int argc, char *argv[])
{
cout << "There are " << argc << " arguments:" << endl;
// Loop through each argument and print its number and value
for (int i=0; i<argc; i++)
cout << i << " " << argv[i] << endl;
return 0;
}
I get what I expect and my arguments are printed out.
However, if I use _tmain:
int _tmain(int argc, char *argv[])
{
cout << "There are " << argc << " arguments:" << endl;
// Loop through each argument and print its number and value
for (int i=0; i<argc; i++)
cout << i << " " << argv[i] << endl;
return 0;
}
It just displays the first character of each argument.
What is the difference causing this?

_tmain does not exist in C++. main does.
_tmain is a Microsoft extension.
main is, according to the C++ standard, the program's entry point.
It has one of these two signatures:
int main();
int main(int argc, char* argv[]);
Microsoft has added a wmain which replaces the second signature with this:
int wmain(int argc, wchar_t* argv[]);
And then, to make it easier to switch between Unicode (UTF-16) and their multibyte character set, they've defined _tmain which, if Unicode is enabled, is compiled as wmain, and otherwise as main.
As for the second part of your question, the first part of the puzzle is that your main function is wrong. wmain should take a wchar_t argument, not char. Since the compiler doesn't enforce this for the main function, you get a program where an array of wchar_t strings are passed to the main function, which interprets them as char strings.
Now, in UTF-16, the character set used by Windows when Unicode is enabled, all the ASCII characters are represented as the pair of bytes \0 followed by the ASCII value.
And since the x86 CPU is little-endian, the order of these bytes are swapped, so that the ASCII value comes first, then followed by a null byte.
And in a char string, how is the string usually terminated? Yep, by a null byte. So your program sees a bunch of strings, each one byte long.
In general, you have three options when doing Windows programming:
Explicitly use Unicode (call wmain, and for every Windows API function which takes char-related arguments, call the -W version of the function. Instead of CreateWindow, call CreateWindowW). And instead of using char use wchar_t, and so on
Explicitly disable Unicode. Call main, and CreateWindowA, and use char for strings.
Allow both. (call _tmain, and CreateWindow, which resolve to main/_tmain and CreateWindowA/CreateWindowW), and use TCHAR instead of char/wchar_t.
The same applies to the string types defined by windows.h:
LPCTSTR resolves to either LPCSTR or LPCWSTR, and for every other type that includes char or wchar_t, a -T- version always exists which can be used instead.
Note that all of this is Microsoft specific. TCHAR is not a standard C++ type, it is a macro defined in windows.h. wmain and _tmain are also defined by Microsoft only.

_tmain is a macro that gets redefined depending on whether or not you compile with Unicode or ASCII. It is a Microsoft extension and isn't guaranteed to work on any other compilers.
The correct declaration is
int _tmain(int argc, _TCHAR *argv[])
If the macro UNICODE is defined, that expands to
int wmain(int argc, wchar_t *argv[])
Otherwise it expands to
int main(int argc, char *argv[])
Your definition goes for a bit of each, and (if you have UNICODE defined) will expand to
int wmain(int argc, char *argv[])
which is just plain wrong.
std::cout works with ASCII characters. You need std::wcout if you are using wide characters.
try something like this
#include <iostream>
#include <tchar.h>
#if defined(UNICODE)
#define _tcout std::wcout
#else
#define _tcout std::cout
#endif
int _tmain(int argc, _TCHAR *argv[])
{
_tcout << _T("There are ") << argc << _T(" arguments:") << std::endl;
// Loop through each argument and print its number and value
for (int i=0; i<argc; i++)
_tcout << i << _T(" ") << argv[i] << std::endl;
return 0;
}
Or you could just decide in advance whether to use wide or narrow characters. :-)
Updated 12 Nov 2013:
Changed the traditional "TCHAR" to "_TCHAR" which seems to be the latest fashion. Both work fine.
End Update

the _T convention is used to indicate the program should use the character set defined for the application (Unicode, ASCII, MBCS, etc.). You can surround your strings with _T( ) to have them stored in the correct format.
cout << _T( "There are " ) << argc << _T( " arguments:" ) << endl;

Ok, the question seems to have been answered fairly well, the UNICODE overload should take a wide character array as its second parameter. So if the command line parameter is "Hello" that would probably end up as "H\0e\0l\0l\0o\0\0\0" and your program would only print the 'H' before it sees what it thinks is a null terminator.
So now you may wonder why it even compiles and links.
Well it compiles because you are allowed to define an overload to a function.
Linking is a slightly more complex issue. In C, there is no decorated symbol information so it just finds a function called main. The argc and argv are probably always there as call-stack parameters just in case even if your function is defined with that signature, even if your function happens to ignore them.
Even though C++ does have decorated symbols, it almost certainly uses C-linkage for main, rather than a clever linker that looks for each one in turn. So it found your wmain and put the parameters onto the call-stack in case it is the int wmain(int, wchar_t*[]) version.

With a little effort of templatizing this, it wold work with any list of objects.
#include <iostream>
#include <string>
#include <vector>
char non_repeating_char(std::string str){
while(str.size() >= 2){
std::vector<size_t> rmlist;
for(size_t i = 1; i < str.size(); i++){
if(str[0] == str[i]) {
rmlist.push_back(i);
}
}
if(rmlist.size()){
size_t s = 0; // Need for terator position adjustment
str.erase(str.begin() + 0);
++s;
for (size_t j : rmlist){
str.erase(str.begin() + (j-s));
++s;
}
continue;
}
return str[0];
}
if(str.size() == 1) return str[0];
else return -1;
}
int main(int argc, char ** args)
{
std::string test = "FabaccdbefafFG";
test = args[1];
char non_repeating = non_repeating_char(test);
Std::cout << non_repeating << '\n';
}

Related

Passing parameters from command line to C++

Searching the net for examples how to pass command line parameters to a C++ code, I came up with an abandoned post where this process is being explained. This code was not working and after a few amendments I came up with the following (working) code:
#include <iostream>
#include <windows.h>
#include <fstream>
#include <string>
using namespace std;
// When passing char arrays as parameters they must be pointers
int main(int argc, char* argv[]) {
if (argc < 2) { // Check the value of argc. If not enough parameters have been passed, inform user and exit.
std::cout << "Usage is -i <index file name including path and drive letter>\n"; // Inform the user of how to use the program
std::cin.get();
exit(0);
} else { // if we got enough parameters...
char* indFile;
//std::cout << argv[0];
for (int i = 1; i < argc; i++) { /* We will iterate over argv[] to get the parameters stored inside.
* Note that we're starting on 1 because we don't need to know the
* path of the program, which is stored in argv[0] */
if (i + 1 != argc) {// Check that we haven't finished parsing already
if (strcmp(argv[i],"/x")==0) {
// We know the next argument *should* be the filename:
char indFile=*argv[i+1];
std::cout << "This is the value coming from std::cout << argv[i+1]: " << argv[i+1] <<"\n";
std::cout << "This is the value of indFile coming from char indFile=*argv[i+1]: " <<indFile <<"\n";
} else {
std::cout << argv[i];
std::cout << " Not enough or invalid arguments, please try again.\n";
Sleep(2000);
exit(0);
}
//std::cout << argv[i] << " ";
}
//... some more code
std::cin.get();
return 0;
}
}
}
Executing this code from the Windows command line using:
MyProgram.exe /x filename
returns the next output:
This is the attribute of parameter /x: filename
This is the value from *argv[i+1]: f
The original post from cplusplus.com did not compile; the code above does.
As you can see printing the argv[2] gives me the name of the file. When I try to capture the file name into another var so I can use it in the C++ program, I only get the first character (second response line).
Now for my question: How can I read the value from the command line parameter the pointer is pointing to?
Hope someone can help this newbie in C++ :-)
*argv[i+1]
Accesses the 1st char of the char* argv[] argument.
To get the whole value use something like
std::string filename(argv[i+1]);
instead.
You can't store a string in a single char.
Here's the once-an-idiom for copying the main arguments to more manageable objects:
#include <string>
#include <vector>
using namespace std;
void foo( vector<string> const& args )
{
// Whatever
(void) args;
}
auto main( int n, char* raw_args[] )
-> int
{
vector<string> const args{ raw_args, raw_args + n };
foo( args );
}
Do note that this code relies on an assumption that the encoding used for the main arguments can represent the actual command line arguments. That assumption holds in Unix-land, but not in Windows. In Windows, if you want to deal with non-ASCII text in command line arguments, you'd better use a third party solution or roll your own, e.g. using Windows' GetCommandLine API function.

C++ command line argument for .exe program

I have program.exe that is being created on my Windows machine. For some reason I am not able to pass in command line arguments properly.
int main(int argc, char *argv[]) {
///////testing
cout << "\n\n(int)ARGV[1]: " << (int)argv[1] << "\n\n";
return 0;
}
In terminal I run:
program.exe 4
I see (int)ARGV[1]: 15333464 printed to my console.
Why does this happen, and how I can modify the code? I should get the number 4 printed out.
When you cast from char* to int you get the pointer value bitpattern interpreted as an integer.
A good way to instead interpret the character string pointed to, as a specification of an integer, is to use std::stoi from the <string> header.
Thus:
#include <iostream>
#include <stdlib.h> // EXIT_FAILURE
#include <string> // std::stoi
using namespace std;
int main(int argc, char *argv[])
{
if( argc != 2 )
{
return EXIT_FAILURE;
}
cout << "ARGV[1]: " << stoi( argv[1] ) << "\n";
}
For the case where the argument isn't a valid specification of an integer, stoi will throw an exception, and in the code above that will cause the program to terminate with some message displayed – a crash. That's generally preferable to producing incorrect results. But if you want to handle it, read up on try and catch in your C++ textbook.
If you want filenames as command line arguments, and more generally filesystem paths, then do note that the Windows convention for encoding of char based strings is Windows ANSI, which has a very limited set of characters. Some filenames and paths on my Norwegian computer can't be represented in your Windows ANSI (yes, Windows ANSI is locale-specific). So for this the C and C++ main argument mechanism, is ungood.
The Windows API provides a pair of wchar_t based functions that can be used as a (working) alternative, namely GetCommandLine (retrieves the raw UTF-16-encoded command line) and CommandLineToArgvW (standard parsing to produce individual arguments).
Some Windows compilers also provide an alternative to standard main called wmain, where argv is declared as wchar_t* argv[]. These compilers include Visual C++ and the MinGW64 variant of g++.
Here argv[1] is a character pointer (char*) so you cant convert a character pointer to an integer by type casting. So to convert the character pointer to an integer use the atoi() function, which is available in the c standard library (include the cstdlib library).
#include <iostream>
#include <cstdlib>
using std::cout;
using std::endl;
using std::atoi;
int main(int argc, char *argv[])
{
cout << atoi(argv[1]) << " " << endl;
return 0;
}
Note that atoi() returns zero if the argument passed to it cannot be converted to an integer. So you could check the returned value and if it is zero then print the relevant message.
Thus:
#include <iostream>
#include <cstdlib>
#include <cstring>
using std::atoi;
using std::cout;
using std::endl;
using std::strcmp;
int main(int argc, char *argv[])
{
if(argc == 2)
{
if(atoi(argv[1]) == 0 && strcmp(argv[1], "0") != 0)
cout << "The argument supplied is not an integer" << endl;
else
cout << atoi(argv[1]) << " " << endl;
}
else if( argc > 2)
cout << "Too many arguements" << endl;
else
cout << "Insufficient arguements" << endl;
return 0;
}

C++ arguments comparison

Hello I am trying to read some arguments and process them but when i try to read arguments via if else ladder a problem occurs
int main (int argc, char *argv[])
{
cout << argv[1] << endl;
if (argv[1] == "process")
cout << "yes" << endl;
else
cout << "no" << endl;
}
This code outputs:
process
no
Do you know why the output is no instead of yes?
By the way I tried to convert either one of them to a string and compared it with another surprisingly it worked, even though I couldn't figure out why.
argv[1] is a pointer, actually a char * (see the definition char *argv[]), and in your code "process" (which is a const char []) also decays to a const char *, so you are basically comparing two char *.
Since char * are simply pointers, then you are comparing addresses, not "string", and obviously argv[1] and "process" are not stored at the same address.
If you convert one of the two to std::string, then you are comparing a std::string and char * (or const char *), and std::string has an overloaded operator== for char * so it works.
You could compare "C strings" (aka char arrays) using strcmp or strncmp.
argv[1] == "process" compares pointers. Use strcmpto compare the strings behind the pointers:
#include <string.h>
int main (int argc, char *argv[])
{
cout << argv[1] << endl;
if (strcmp(argv[1],"process")==0)
cout << "yes" << endl;
else
cout << "no" << endl;
}

Printing parameters in win32 console application

Here's my code:
int _tmain(int argc, _TCHAR* argv[])
{
for (int i = 1;i<argc;i++) printf("Argument %d:%s\n",i,argv[i]);
// output = Argument 1:param
for (int k = 1; k < argc; k++) cout << "Argument " << k << ": " << argv[k];
// output = Argument 1: 00BF5878
return(0);
}
My question is: why do I see different outputs on cout and printf?
You see an address in the output from cout because you have built the program with UNICODE or _UNICODE defined. Probably by way of a setting in a Visual Studio project. Then _tmain expands to MIcrosoft's non-standard wmain, and _TCHAR expands to wchar_t.
And cout doesn't know how that a pointer to wchar_t is supposed to point to a null-terminated string of wide characters.
I am not sure why that doesn't happen with printf. Lemme check.
OK I have checked and your printf is not printing "param" as you indicate it does.
Here's the corrected code I checked with:
#include <iostream>
#include <stdio.h>
#include <tchar.h>
using namespace std;
int _tmain( int argc, _TCHAR* argv[] )
{
for( int i = 0;i < argc; ++i )
{
printf("printf Argument %d:%s\n",i,argv[i]);
}
for( int i = 0; i < argc; ++i )
{
cout << "cout Argument " << i << ": " << argv[i] << endl;
}
}
And here's the result:
[D:\dev\test]
> cl foo.cpp /D _UNICODE
foo.cpp
[D:\dev\test]
> foo param
printf Argument 0:f
printf Argument 1:p
cout Argument 0: 004F9A9C
cout Argument 1: 004F9AA4
[D:\dev\test]
> _
In other words, the apparent conundrum is entirely caused by your inaccurate reporting of results.
Solution: instead of using Microsoft's non-standard wmain, and in particular instead of using the now totally meaningless Windows 9x support macros!, use a standard C++ main.
The difference is that printf takes the contents of the parameters and forces the data to match the format specifier. The content of argv[i] will be treated as a nul terminated string because of the %s format specifier.
The cout in conjunction with the stream insertion operator will output based on the type of the parameter. The compiler will search all the operator<<() methods for cout and choose the one the best matches the parameter.
In your case, the compiler is looking for the method operator<<(TCHAR *) and didn't find an exact match. Instead, the compiler recognized that the parameter was a pointer and chose operator<<(void *) which prints out a pointer.
Try defining operator<<(TCHAR*) and see what happens.

problem with reading program arguments in Visual Studio C++

I'm running C++ program in VS2005, and I've set only one argument in project properties-> debug-> command line args, and it's named profile1.dll for example.
here's a code snippet
cout<<"number of arguments:" << argc<<endl;
for (int i=0; i<argc; i++)
cout << "argument " << i << ": " << argv[i] << endl;
In the output I get
number of arguments:2
argument 0: c
argument 1: p
don't know why it doesn't print the name of the argument?
Does the name of your exe start with C? If you expect a string and you only get one character, it's usually because you've discovered that the Western alphabet in UTF-16 Unicode effectively puts a 0 between alternating ANSI chars. Are you compiling for Unicode ?
argv[0] is the name of your program. argv[1] is the first parameter. It sounds like you have declared the relevant parameter in main() as char* argv rather than char *argv[] or char **argv.
Leave TCHAR be, it's fine.
If you compile with unicode, use wcout for output:
int _tmain(int argc, _TCHAR* argv[])
{
for (int i=0; i<argc; i++)
wcout << "argument " << i << ": " << argv[i] << endl;
return 0;
}
Otherwise compile without unicode and your code will just work as-is (and will not work with unicode parameters :o)
You can find setting in "Project Properties/General/Character Set"
Can you put the prototype of your main function? What you are doing is apparently fine.
Make sure your main's function prototype is something similar to:
int main(int argc, char **argv)
Hope it helps.