I noticed by chance that the following code
var
I: Integer;
begin
I:= StrToInt('0xAA');
ShowMessage(IntToStr(I)); // shows 170 = $AA
end;
is OK in Delphi 2009. BTW the feature helped me to extract hexadecimal constants from C header file.
I wonder is it OK to use the feature or the feature is about to be "fixed" in future versions?
It's a feature, and you can rely on it. One of the philosophical changes that occurred in the evolution of Turbo Pascal into Delphi was the acknowledgment that Delphi lives in a C-dominated world and there was more to be gained by gracefully accepting or tolerating C-isms than ignoring them and forcing the Delphi developer to sort it out. Interop with C++ Builder as mentioned by Rob was a factor, but so was the fact that Delphi was designed first for Windows, and Windows has a lot of C language artifacts in the Windows API.
I think the term "impedance mismatch" may apply here - it was simple enough to remove the impedance mismatch between Delphi hex handling and "Rest of World", so we did.
Recall that the Delphi RTL is used by C++ Builder, too. The documentation doesn't go into detail about exactly what it means when it says StrToIntaccepts "decimal or hexadecimal notation." You can safely expect StrToInt to continue to accept C-style numbers.
Val accepts the same input, as does Read (because they all end up calling System._ValLong).
Related
Consider the code:
procedure DoSmthSecret;
var
Seed: array[0..31] of Byte;
begin
// get random seed
..
// use the seed to do something secret
..
// erase the seed
FillChar(Seed, SizeOf(Seed), 0);
end;
The problem with the code is: FillChar is a compiler intrinsic, and potentially a compiler can "optimize it out". The problem is known for C/C++ compilers, see SecureZeroMemory. Can modern Pascal compiler (Delphi, FPC) do such optimization, and if they can, do they provide SecureZeroMemory equivalent?
FPC can't do such optimizations at the moment, and afaik even with C++ they belong into the "uncertain" class. (since the state of the program due to this optimization ignores what the programmer tells it to be)
Solving such problem is a matter of defining which constructs can be optimized out and which not. It doesn't need API/OS assistance per se, any externally linked object file with such function would do (since then global optimization wouldn't touch it)
Note that the article doesn't name the C++ compiler specifically, so I expect it is more a general utility function for when an user of a compiler gets into problems, without hitting the docs too hard, or when it must easily work on multiple (windows-only!) compilers without overly complicating the buildsystem.
Choosing a non inlinable API function might be non optimal in other cases, specially with small, constant sizes to zero, since it won't be inlined, so I would be careful with this function, and make sure there is a hard need
It might be important mainly when an external entity can change memory (DMA, memory mapping etc) of a program, or to erase passwords and other sensitive info from the memory image, even if the program according to the compiler will never read it
Even if FreePascal would optimize out writing to memory that is never read again (which I doubt it does atm, regardless of how long you guys discuss it), it does support the absolute type modifier which it guarantees (documented) to never optimize (somewhat similar to volatile in C/C++).
I just came across an answer on SO with a curious syntax:
How do I include a newline character in a string in Delphi?
MyString := 'Hello,' + ^M + ^J + 'world!';
I've been using Delphi for several years now, but I didn't know you could use the circumflex sign for control characters.
Is this just a left over from the early Delphi or Turbo Pascal days?
Should it be used nowadays?
PS: I'm not asking about advice on the line break characters, there is sLineBreak and other methods as discussed in the original question.
No, it is not from Turbo Pascal days. It is from decades before TP, and before MS-DOS, and probably even before UNIX. Something old like first 300 bit-per-second dialup modems and DEC VT-52 terminal, RT-8 OS on PDP-8 machine and early version of C. Or maybe even older - though everything older to me is mere legends :-).
"^" sign is shortcut for "Ctrl" key. So ^C in traditional notation stands for Ctrl+C in Microsoft notation. That notation was vastly used for textmode menus in MS-DOS times, like in the aforementioned Turbo Pascal, Norton Utilities, DOS Navigator, etc.
Out of my memory you can consider "^" for "subtract 64".
So as Chr(65) is 'A' then Chr(1) would be ^A.
And ^# would be #0 :-) AFAIR in MS-DOS times pressing Ctrl+Shift+"2/#" would actually produce #0 into BIOS keyboard buffer :-)
^[ would AFAIR be #27 aka Esc(ape) char - and if you run telnet.exe you would see it prompted as the escape character.
So Turbo Pascal long ago chosen to follow the time-blessed convention, and then rules of backward compatibility engaged ever since. Personally, i take 'bla-bla'^M^J'foo-baz' literal more string-like than 'bla-bla'#13#10'foo-baz' when you want it on one line. And constructing the value with plus is better fit when your literal takes several source lines.
The pity is that syntax highlighting in Delphi IDE is hopelessly broken on that kind of constants.
Yes this is a legacy from days of yore.
And no you should not get into the habit of using this feature. Remember that code is read more often than it is written. Always think of your readers who most likely won't know what that syntax means.
Yes, this is left over from TP days. You could also write your statement like this
mystring:= 'Hello'#13#10'world!';
which is probably less obscure and more easily understandable than using ^M and ^J. Of course, you should really define constants
const
crlf = #13#10
begin
mystring:= 'Hello' + crlf + 'world!';
end;
In Delphi XE or 2006, is there any way to detect at compile time that implicit conversions between integer types may lose data? I realize it's possible to detect this with runtime checking. I would want it to flag the following example even if the "big" value were 1. (We're considering changing int to bigint for certain database keys and want to determine the impact on a large legacy codebase.)
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
small: Integer;
big: Int64;
begin
big := 3000000000000;
small := big; // Detect me!
Writeln(small);
end.
You won't get any warnings or hints at compile time. The Delphi compiler does not do any program flow analysis which tells it that big contains a too large value when it is assigned to small. It silently truncates the value to make it fit in the smaller type. I tried with Shortint, a signed byte-sized type and even that did not give a warning or hint.
And there is no way to make Delphi warn you. It would be nice. Perhaps you can suggest it in QC (if it wasn't already suggested)?
In Delphi, even in Delphi 10.3 -- no.
But take a look into software calling 'Pascal Analyzer', mfg by www.peganza.com
They have a lot of options and one of them is (taken from software Help):
Source code for test, take a look into line #32:
Analyze result show possible bad assignment in line #32:
Sorry about my english...
I'm trying to make a small program in Delphi 7.
Its interface will have text in my language, which has some characters with diacritics.
If "Language for non-Unicode programs" is set to my language those characters are always displayed fine. That's normal.
If is set to something else, sometimes are displayed fine, sometimes they are not.
How can I know that they can be displayed fine or not...?
Oh, and I can't use Unicode components, only normal.
Only way that I found is to capture the image of one characters into a bitmap and check pixel by pixel. But it's a lot of work to implement, slow and imprecise.
I can use GetSystemDefaultLangID function and know that "Language for non-Unicode programs" is set to something else but still don't know if they are displayed fine or not.
Thank you for any idea.
Welcome to the joys of AnsiStrings encoded using code-pages. You should not be using AnsiStrings at all, and you know that, but you say without explaining it that you can't use unicode controls. this seems strange to me. You should be using either:
(a) A Unicode version of Delphi (2009,2010, XE), where String=UnicodeString.
(b) If not that, at least use Proper Unicode controls, such as TNT Controls, and internally use WideString types where you need to store accented or international characters.
Your version of Delphi has String=AnsiString, and you are relying on the locale that your system is set to (as you say in your question) to select the codepage representations of accented characters, a problematic scheme. If you really can't move up from Delphi 7, at least start using WideStrings, and TNT Unicode Controls, but I must say that effort is WASTED you would be better off getting Delphi XE, and just porting to Unicode.
Your question asks "how can I know if they can be stored fine or not?" You can encode and decode using your codepage, and check if anything is replaced with a "?". The windows function WideCharToMultiByte, for example behaves like this. MBCS is a world of pain, and not worth doing, but you asked how you can find out where the floor falls out from under you, so that API will help you understand your selected encoding rule.
Use WideCharToMultiByte Function - http://msdn.microsoft.com/en-us/library/dd374130(v=vs.85).aspx and check lpUsedDefaultChar parameter.
Since this has been on my research list for a while, but didn't reach the top of that list yet, I can only help you out with a few links.
You will need to to quite a bit of experimentation :-)
When using Unicode, you can use functions ScriptGetCMap and GetGlyphIndices to test if a code point is in the font.
When not using Unicode, you can use the function GetGlyphIndices
There are few Delphi translations of these functions around. This Borland Newsgroup thread has a few hints on using GetGlyphIndices in Delphi.
Here is a search ScriptGetCMap in Delphi.
This page has a list of some interesting API calls that might help you further.
An extra handicap is that because not all fonts contain all characters, so Windows can do font substitution for you.
I'm not sure how to figure out that, but it is something you have to check for too.
Good luck :-)
procedure TForm1.Button2Click(Sender: TObject);
var
ACP: Integer;
begin
ACP := GetACP;
Caption := 'CP' + IntToStr(ACP);
if ACP = 1250 then
Caption := Caption + ' is okay for Romanian language';
end;
Let me explain by an example. In Delphi, you can write
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = ^C then
ShowMessage('The user wants to copy something.')
else if Key = ^V then
ShowMessage('The user wants to paste.')
end;
to check for Ctrl+C and Ctrl+V keyboard commands. In fact, the same syntax works for Ctrl+A, where A is any character, and -- of course -- you can also use a case statement instead of ifs. You can even do ShowMessage(^A), so, apparently, ^A is considered a char.
However, when browsing the official Delphi documentation, I cannot find any reference to this syntax. But maybe the ^A syntax is so common that it is understood as a part of the underlying plain text file format? Or is it simply an undocumented feature of the Delphi programming language? (Notice that the above constructions are actually used in the RTL/VCL source code. But, of course, Embarcadero, and Embarcadero alone, is allowed to use undocumented features, if any such exists.)
This is from long ago as an escape character to enable you to have consts for control characters in a more readable way.
const
CtrlC = ^C;
begin
Write(Ord(CtrlC));
end.
This defines a Char constant with value #3, then writes 3 in Borland Pascal 7, and I remember seeing it years before that too.
I just checked the Turbo Pascal 5.0 and Borland Pascal 7.0 languages guides, but could not find it, so it seems undocumented.
Edit:
I do remember this was a Borland thing, and just checked: it is not part of the ISO Pascal standard (formerly this was ANSI Pascal Standard, thanks Sertac for noticing this).
It is documented in the Free Pascal documentation.
SGI uses the backslash as escape character, as per their docs.
More Edit: I found it documented in Delphi in a Nutshell and the Delphi Basics site.
Found it: Just found it on page 37 of the Turbo Pascal 3 Reference Manual.
--jeroen
This is a known undocumented feature. But then again, the latest official syntax documentation is from delphi 7.