Command Line arguments handling on Visual C++ 2010 [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between _tmain() and main() in C++?
I have a console application, which takes one command line parameter.
int _tmain(int argc, char* argv[])
{
...
printf("Path: %s\n", argv[1]);
...
}
When I run the program with an argument (myprogram.exe D:\myfolder\myfile), it prints Path: D instead of Path: D:\myfolder\myfile.
How should I change the procedure for extracting first command-line parameter (argv[1]) so that it returns the full path, not just the first letter?
I tried to put the path in quotes (myprogram.exe "D:\myfolder\myfile"), but it didn't help.

Use _tprintf instead of printf. Your program is almost certainly set to compile as UNICODE and, therefore, each "character" takes up two bytes.
You call printf which operates on single byte characters. The second byte happens to be 0, and so printf thinks it reached the end of the string since a zero byte is considered the termination of a string.
And make sure your argv is declared as TCHAR and not char. Be consistent: either use the TCHAR routines, or don't. But don't mix unless you have a very good reason (i.e. you know what you're doing and you are gearing up to do some magic). Chances are you don't and you shouldn't.

Visual Studio C++ has a special way of dealing with Unicode support. Macros in tchar.h expand to normal or wide char versions of the symbols depending on the project setting. So _tprintf expands to printf or wprintf. It seems like you're trying to use printf, if your project settings enable the Unicode support, what you're running into is the exact problem to expect. Have a look at tchar.h and try using _tprintf instead.

In visual studio the main function usually takes up the arguments of type wchar. If that is the case try outputting via the wprintf function as:
wprintf("Path : %S", argv[1]);
Notice the capital 'S'. If you substitute this with a lowercase 's' it will print the first character only. That is how the wide characters work. you should read more about them on the msdn forum.

Related

standard main and unicode, managing console input and output

The standard recognizes int main() and int main(int, char* []) entry points, and there is no unicode version of the function, except of course if provided by implementation such as wmain on windows.
I have code which strictly uses 'wide' strings ie. wchar_t and std::wstring not even a single LOC makes any use of char type.
Also all the 'program output' is printed with std::wcout.
Now I do understand when the program starts it's stream will be set to 'wide' stream, and even if somewhere in the code std::cout appears instead of std::wcout then output may be wrong.
Now my first misunderstanding is, if a user runs several command line tools in same terminal (ie. cmd.exe) where one program uses wide string and other uses ASCII strings then what is the behavior of the terminal?
Does it handle both streams just fine? is wide stream and non wide stream related to program and not to terminal?
Secondly, my main issue is that my 'unicode' program expects user input, which will most likely be char because int main(int, char* []) accepts char string, but my code uses wide strings.
What are my options here? do I need to convert input non unicode strings to wide strings?
And what happens if I use int wmain(int, wchar_t* []) on windows? how do I know if terminal will interpret user input as wide characters and forward them to my entry point?
what if user copy/pastes ASCII string into the console as input to my entry point?
So my questions are, console program input and output char and wchar_t in both portable and non portable code, missing wide main function by standard is what confuses me most in combination with different terminals.
edit
To be clear,
I want to use standard main and wide strings.
my code uses wide string.
my program expects user input, and writes output. so how to best handle this?
Is wmain the only solution to get unicode input and how do terminals work in regard to unicode vs non unicode with different programs in same console session.

__int64 to CString returns wrong values - C++ MFC

I want to convert a __int64 variable into a CString. The code is exactly this
__int64 i64TotalGB;
CString totalSpace;
i64TotalGB = 150;
printf("disk space: %I64d GB\n", i64TotalGB);
totalSpace.Format(_T("%I64d", i64TotalGB));
printf("totalSpace contains: %s", totalSpace);
the first printf prints
"disk space: 150GB"
which it's correct, but the second printf prints randomly high numbers like
"totalSpace contains: 298070026817519929"
I also tried to use a INT64 variable instead of a __int64 variable, but the result is the same. What can be the cause of this?
Here:
totalSpace.Format(_T("%I64d", i64TotalGB));
you're passing i64TotalGB as an argument to the _T() macro instead of passing it as the second argument to Format().
Try this:
totalSpace.Format(_T("%I64d"), i64TotalGB);
Having said that, thanks to MS's mess (ha) around character encodings, using _T here is not the right thing, as CString is composed of a TCHAR and not _TCHAR. So taking that into account, might as well use TEXT() instead of T(), as it is dependent on UNICODE and not _UNICODE:
totalSpace.Format(TEXT("%I64d"), i64TotalGB);
In addition, this line is wrong as it tries to pass an ATL CString as a char* (a.k.a. C-style string):
printf("totalSpace contains: %s", totalSpace);
For which the compiler gives this warning:
warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'ATL::CString'
While the structure of CString is practically compatible with passing it like you have, this is still formally undefined behavior. Use CString::GetString() to safeguard against it:
printf("totalSpace contains: %ls", totalSpace.GetString());
Note the %ls as under my configuration totalSpace.GetString() returned a const wchar_t*. However, as "printf does not currently support output into a UNICODE stream.", the correct version for this line, that will support characters outside your current code page, is a call to wprintf() in the following manner:
wprintf("totalSpace contains: %s", totalSpace.GetString());
Having said ALL that, here's a general advice, regardless of the direct problem behind the question. The far better practice nowadays is slightly different altogether, and I quote from the respectable answer by #IInspectable, saying that "generic-text mappings were relevant 2 decades ago".
What's the alternative? In the absence of good enough reason, try sticking explicitly to CStringW (A Unicode character type string with CRT support). Prefer the L character literal over the archaic data/text mappings that depend on whether the constant _UNICODE or _MBCS has been defined in your program. Conversely, the better practice would be using the wide-character versions of all API and language library calls, such as wprintf() instead of printf().
The bug is a result of numerous issues with the code, specifically these 2:
totalSpace.Format(_T("%I64d", i64TotalGB));
This uses the _T macro in a way it's not meant to be used. It should wrap a single character string literal. In the code it wraps a second argument.
printf("totalSpace contains: %s", totalSpace);
This assumes an ANSI-encoded character string, but passes a CString object, that can store both ANSI as well as Unicode encoded strings.
The recommended course of action is to drop generic-text mappings altogether, in favor of using Unicode (that's UTF-16LE on Windows) throughout1. The generic-text mappings were relevant 2 decades ago, to ease porting of Win9x code to the Windows NT based products.
To do this
Choose CStringW over CString.
Drop all occurences of _T, TEXT, and _TEXT, and replace them with an L prefix.
Use the wide-character version of the Windows API, CRT, and C++ Standard Library.
The fixed code looks like this:
__int64 i64TotalGB;
CStringW totalSpace; // Use wide-character string
i64TotalGB = 150;
printf("disk space: %I64d GB\n", i64TotalGB);
totalSpace.Format(L"%I64d", i64TotalGB); // Use wide-character string literal
wprintf(L"totalSpace contains: %s", totalSpace.GetString()); // Use wide-character library
On an unrelated note, while it is technically safe to pass a CString object in place of a character pointer in a variable argument list, this is an implementation detail, and not formally documented to work. Call CString::GetString() if you care about correct code.
1 Unless there is a justifiable reason to use a character encoding that uses char as its underlying type (like UTF-8 or ANSI). In that case you should still be explicit about it by using CStringA.
try this
totalSpace.Format(_T("%I64d"), i64TotalGB);

Weird behavior of printf in C++ with a newline character

This could be simple or lame question. I have been playing with printf function in C++. When I execute following code on Debian Wheezy with any 9 character argument (eg:"argument1") ;
#include<stdio.h>
int main(int argc, char** argv){
printf(argv[1]+'\n');
}
the out put was;
SSH_AGENT_PID=4375
Then I checked the environment variable $SSH_AGENT_PID and its value is 4375.
Could you please tell me what is going on with my code ?
(I tried to examine the disassembled code in gdb. But my assembly knowledge is poor to understand exactly whats going on)
Simple fix:
printf("%s\n", argv[1]);
This is an improvement on your code for two reasons: First, it's generally a good idea to have the first argument to printf be a string constant, as this prevents printf code injection. Second, it fixes the bug because as #Captain Oblivious pointed out, the code you wrote doesn't do what you think it does.
char* strings and string literals and character literals can't be added together. You need to create a new string and use strcat to concatenate one to the other.
What you're actually getting is undefined behavior, since you're adding some constant to a pointer and not checking that you've passed the end of the string. It's only a coincidence that the output was readable at all and that your program didn't crash.
If C++ is an option you can use std::string instead, which does allow + to concatenate two strings.
To explain what you are seeing from argv[1] + '\n'. This is pointer plus integer (character constants have type int in C).
The definition of that in C is that the pointer is advanced by as many units as are in the integer. \n is 10 in ASCII so this will advance the pointer by 10 characters. If your string is shorter than 10 then you're now reading whatever is in memory beyond the end of that string.
The fix suggested by Ben Braun is a good one; another option is puts( argv[1] ); which will output the string without doing any printf-like translations, and output a newline.

Unicode in C++ support [duplicate]

This question already has answers here:
How well is Unicode supported in C++11?
(5 answers)
Closed 9 years ago.
There are some posts on this matter but I wanted to double check.
In Joel Spoolsky's article (link) one reads:
In C++ code we just declare strings as wchar_t ("wide char") instead
of char and use the wcs functions instead of the str functions (for
example wcscat and wcslen instead of strcat and strlen). To create a
literal UCS-2 string in C code you just put an L before it as so:
L"Hello".
My question is: Is what is written above, not enough to support Unicodes in a C++ app?
My confusions started when I couldn't output simple text like (in Russian):
wcout<<L"логин";
in console.
Also, recently I saw some code written for an embedded device where one person handles I think Unicode related strings using wchar_t.
Any help greatly appreciated.
This works in C++11 on a linux, utf8 machine:
#include <iostream>
int main(int, char**) {
std::cout << u8"Humberto Massa Guimarães\nлогин\n";
}
First, you can not print non-english characters in command-line
Second, briefly; UNICODE uses two bytes for every character and char uses single byte. For example string "ABC" will be stored in char as ABC\0 (3 bytes + end_of_string_character)
but in UNICODE will be stored as A\0B\0C\0\0\0 (6 + end_of_string_character which is two bytes like other characters)
For view some text, I suggest you to MessageBoxW:
First include windows header file: #include <windows.h>
Second use MessageBoxW API function:
MessageBoxW(0, L"UNICODE text body", L"title", MB_ICONINFORMATION);

dmDeviceName is just 'c'

I'm trying to get the names of each of my monitors using DEVMODE.dmDeviceName:
dmDeviceName
A zero-terminated character array that specifies the "friendly" name of the printer or display; for example, "PCL/HP LaserJet" in the case of PCL/HP LaserJet. This string is unique among device drivers. Note that this name may be truncated to fit in the dmDeviceName array.
I'm using the following code:
log.printf("Device Name: %s",currDevMode.dmDeviceName);
But for every monitor, the name is printed as just c. All other information from DEVMODE seems to print ok. What's going wrong?
Most likely you are using the Unicode version of the structure and thus are passing wide characters to printf. Since you use a format string that implies char data there is a mis-match.
The UTF-16 encoding results in every other byte being 0 for characters in the ASCII range and so printf thinks that the second byte of the first two byte character is actually a null-terminator.
This is the sort of problem that you get with printf which of course has no type-safety. Since you are using C++ it's probably worth switching to iostream based I/O.
However, if you want to use ANSI text, as you indicate in a comment, then the simplest solution is to use the ANSI DEVMODEA version of the struct and the corresponding A versions of the API functions, e.g. EnumDisplaySettingsA, DeviceCapabilitiesA.
dmDeviceName is TCHAR[] so if you're compiling for unicode, the first wide character will be interpreted as a 'c' followed by a zero terminator.
You will need to convert it to ascii or use unicode capable printing routines.