As of Visual Studio 2005, the CRT has replaced most string functions with secure versions which add a size argument to indicate the limits of the destination buffer(s). This is fine, but it’s not clear how it should be used. Does it include the terminating zero? Take the following code for example:
…
TCHAR path[MAX_PATH] = TEXT("");
_tcscpy_s(path, MAX_PATH, filename);
…
Is it okay or does it induce an off-by-one error?
It'd be a failure of the API design to be MAX_PATH+/-1, as that would be confusing and lead to more buffer overflows.
Documentation states clearly for
dest[10] that _countof(dest) should be used, which would be 10
So a simple MAX_PATH will suffice.
Related
I am dealing with very large files, frequently over 2GBs, and need to dump them into a buffer to be able to deal with them.
I create the buffer like this:
char* bigBuffer = nullptr;
...
bigBuffer = new char[3'000'000'000];
The line that allocates the memory shows the following warning when all warnings are enabled: C4310 cast truncates constant value
I tried explicitly telling the compiler this is not an int by changing the line to:
bigBuffer = new char[3'000'000'000ull];
but I'm still getting the same warning. Seems like it is casting it implicitly to an int no matter what.
How do I get the compiler to allow me to create this array in the way I want, or even larger if needed?
I am on the latest version of Visual Studio 2019.
We have to upgrade to XE2 (from Delphi6).
I collected many informations about this, but one of them isn't clear for me.
We are using String - what is AnsiString in XE.
As I know we must replace all (P)Ansi[String/Char] in our libraries to avoid the side effects of Unicode converts, and to we can compile our projects.
It is ok, but we are also using TStringList, and I don't found any TAnsiStringList class to change it simply... ;-)
What do you know about this? Can this cause problems too? Or this class have an option to preserve the strings?
(Ok, it seems to be 3 questions, but it is one only)
The program / OS language is hungarian, the charset is WIN-1250, what have some strange characters, like Ő, and Ű...
Thanks for your every information, link, etc.
1) 1st of all - WHY should u use AnsiStringList, rather than converting all your project to unicode-aware TStringList ? That should have certain detailed reasons, to suggest viable alternatives.
Unicode is a superset of windows-1250, windows-1251 and such.
Normally all you locale-specific string would be just losslessly converted to Unicode. IT is the opposite, Unicode to AnsiString, convertion that may loose data.
Explicit or implicit (like AnsiChar reduction in "if char-var in char-set")
You may have type-unsafe API like in DLLs, where compiler cannot check if you pass PChar or PAnsiChar, but you anyway should not pass objects liek TStrings into DLLs, there are BPLs for that.
So you probably just do not need TAnsiStringList
2) you can take TJclAnsiStringList from Jedi Code Library
3) You can use XE2 stock TList<AnsiString> type
I have the following code:
var wqry:TAdoQuery;
...
FillChar(wSpaces,cSpacesAfter,' ');
try
wqry := TADOQuery.Create(nil);//here the error
wqry.Connection:=...
cSpacesAfter is a constant and has the value 1035. wSpaces is a local string variable. The problem is that I receive the following error when TAdoQuery is created
even it is in french, I believe you got the idea.....
If I comment the FillChar code, everything works ok. I have the usual compiler directives, nothing special. I'm using Delphi 7.
Can someone tell me what is wrong with that code?
The troublesome code is most likely this one
FillChar(wSpaces,cSpacesAfter,' ');
I'm assuming that wSpaces is of string type. A string variable is in fact nothing more than a pointer to the data structure that holds the string. You don't need to use pointer syntax because the compiler takes care of that for you.
So what this code does is overwrite the variable holding that pointer with 4 space characters and then write 1031 more spaces over the top of whatever follows the variable. In short you will completely corrupt your memory. That would explain why the FillChar works but the very next line of code dies a painful and dramatic death.
If your string indeed had space for 1035 characters your could instead write:
FillChar(wSpaces[1], cSpacesAfter, ' ');
However, if may be more idiomatic to write:
wSpaces := StringOfChar(' ', cSpacesAfter);
FillChar procedure fills out a section of storage Buffer with the same byte or character FillValue FillCount times.
It is principally used to initialise arrays of numbers. It can be used to initialise records and strings, but care should be used to avoid overwriting length fields. StringOfChar is best for filling out strings to the same character.
Are you sure wSpaces has the size enough to fit all of cSpacesAfter you write to it?
I'm using Microsoft Visual C++ 2008
I want to join some strings, and then use it with "system" command.
I tried to do it like this:
System::String^ link;
link = "wget.exe --output-document=log http://ADDRESS";
link = link + System::String::Copy(textBox_login->Text);
link = link + "&passwd=";
link = link + System::String::Copy(textBox_passwd->Text);
system(link); //LINE WITH ERROR
But i get error C2664: 'system' : cannot convert parameter 1 from 'System::String ^' to 'const char *'
I appreciate any help ;)
Take a look at this question and this question.
In essence, the problem is that the system function expects a variable of the type const char* rather than System::String.
So you need to convert the string to a const char* (Using code from this answer) and use that as an argument for the system function.
IntPtr p = Marshal::StringToHGlobalAnsi(clistr);
const char* linkStr = static_cast<char*>(p.ToPointer());
system(linkStr);
Marshal::FreeHGlobal(p);
To use system as you do, you will need Marshalling. This requires extra precautions which can lead to unforeseen pain.
I recommend that you call wget via the System::Process class
It integrates with .NET much better and you can use System::String^ directly
after doing as Yacoby said, almost everything works fine, but when it gets to
link = link + "&passwd=";
it cuts everything what is afterwords in string.
when i remove '&' it works just fine... i need the '&' sign
You got the technical solution to your problem but here are a couple other things you might want to consider:
Instead of opening a process to do the HTTP request for you, use an API (.NET or C++, in .NET it's much easier than standard C++, look at WebRequest) to do this. Especially if you plan to do something with the response.
In general if you're appending to a String multiple times, prefer a StringBuilder. Since String is immutable in .NET, every append requires a new String to be constructed.
In this case, don't use a String to build the URL in the first place. Use System::Uri instead.
I'm working on a PInvoke wrapper for a library that does not support Unicode strings, but does support multi-byte ANSI strings. While investigating FxCop reports on the library, I noticed that the string marshaling being used had some interesting side effects. The PInvoke method was using "best fit" mapping to create a single-byte ANSI string. For illustration, this is what one method looked like:
[DllImport("thedll.dll", CharSet=CharSet.Ansi)]
public static extern int CreateNewResource(string resourceName);
The result of calling this function with a string that contains non-ASCII characters is that Windows finds a "close" character, generally this looks like it ends up being "???". If we pretend that 'a' is a non-ASCII character, then passing "cat" as a parameter would create a resource named "c?t".
If I follow the guidelines in the FxCop rule, I end up with something like this:
[DllImport("thedll.dll", CharSet=CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int CreateNewResource([MarshalAs(UnmanagedType.LPStr)] string resourceName);
This introduces a change in behavior; now when a character cannot be mapped an exception is thrown. This concerns me because this is a breaking change, so I'd like to try and marshal the strings as multi-byte ANSI but I cannot see a way to do so. UnmanagedType.LPStr is specified to be a single-byte ANSI string, LPTStr will be Unicode or ANSI depending on the system, and LPWStr is not what the library expects.
How would I tell PInvoke to marshal the string as a multibyte string? I see there's a WideCharToMultiByte() API function, could I change the signature to expect an IntPtr to a string I create in unmanaged memory? It seems like this still has many of the problems that the current implementation has (it still might have to drop or substitute characters), so I'm not sure if this is an improvement. Is there another method of marshaling that I'm missing?
ANSI is multi-byte, and ANSI strings are encoded according to the codepage currently enabled on the system. WideCharToMultiByte works the same way as P/Invoke.
Maybe what you're after is conversion to UTF-8. Although WideCharToMultiByte supports this, I don't think P/Invoke does, since it's not possible to adopt UTF-8 as the system-wide ANSI code page. At this point you'd be looking at passing the string as an IntPtr instead, although if you're doing that, you may as well use the managed Encoding class to do the conversion, rather than WideCharToMultiByte.
Here is the best way I've found to accomplish this. Instead of marshalling as a string, marshal as a byte[]. Put the responsibility on the caller of the pinvoke function API to convert to a byte array in the most appropriate fashion. Most likely by using one of the Text.Encoding classes.
If you end up having to call WideCharToMultiByte manually, I would get rid of the p/invoke and manually marshal this using WideCharToMultiByte in a C++/CLI wrapper function. Managed C++ is much better at these interop scenarios than C# is.
Though, if this is the only p/invoke you have, it's probably not worth it.