tags:

views:

623

answers:

6

The difference between Chr and Char when used in converting types is that one is a function and the other is cast

So: Char(66) = Chr(66)

I don't think there is any performance difference (at least I've never noticed any, one probably calls the other).... I'm fairly sure someone will correct me on this!

EDIT Thanks to Ulrich for the test proving they are in fact identical.
EDIT 2 Can anyone think of a case where they might not be identical, e.g. you are pushed towards using one over the other due to the context?

Which do you use in your code and why?

A: 

Chr is function call, it is a bit (tiny-tiny) more expensive then type cast. But i think Chr is inlined by compiler.

Andrey
+4  A: 

I did a small test in D2007:

program CharChr;

{$APPTYPE CONSOLE}

uses
  Windows;

function GetSomeByte: Byte;
begin
  Result := Random(26) + 65;
end;

procedure DoTests;
var
  b: Byte;
  c: Char;
begin
  b := GetSomeByte;
  IsCharAlpha(Chr(b));
  b := GetSomeByte;
  IsCharAlpha(Char(b));

  b := GetSomeByte;
  c := Chr(b);
  b := GetSomeByte;
  c := Char(b);
end;

begin
  Randomize;
  DoTests;
end.

Both calls produce the same assembly code:

CharChr.dpr.19: IsCharAlpha(Chr(b));
00403AE0 8A45FF           mov al,[ebp-$01]
00403AE3 50               push eax
00403AE4 E86FFFFFFF       call IsCharAlpha
CharChr.dpr.21: IsCharAlpha(Char(b));
00403AF1 8A45FF           mov al,[ebp-$01]
00403AF4 50               push eax
00403AF5 E85EFFFFFF       call IsCharAlpha

CharChr.dpr.24: c := Chr(b);
00403B02 8A45FF           mov al,[ebp-$01]
00403B05 8845FE           mov [ebp-$02],al
CharChr.dpr.26: c := Char(b);
00403B10 8A45FF           mov al,[ebp-$01]
00403B13 8845FE           mov [ebp-$02],al

Edit: Modified sample to mitigate Nick's concerns.

Edit 2: Nick's wish is my command. ;-)

Ulrich Gerhardt
that seems like *cheating*. Try to use a variable instead of a constant. If you'll get the same results I'll upvote your answer :)
Nick D
+1, and if you test `ch := chr(b); ch := char(b);` it'll be perfect.
Nick D
+2  A: 

chr is a function, thus it returns a new value of type char.

char(x) is a cast, that means the actual x object is used but as a different type.

Many system functions, like inc, dec, chr, ord, are inlined.

Both char and chr are fast. Use the one that is most appropriate each time,
and reflects better what you want to do.

Nick D
if they are both identical... (which they seem to be), then how can you tell which one is appropriate, is it more a case of "whichever one you feel like at the time"?
JamesB
@JamesB, I didn't say they're identical. `chr` is a function. On most cases they can be seen as *identical* though.
Nick D
Chr doesn't return a new value, it returns the result of the expression given as the parameter. The expression is evaluated before the call to chr and the call to chr does absolutely nothing.
Uwe Raabe
@Uwe Raabe, ok but that temporary value (eval of the expression) is the *returned* value, no?
Nick D
They are mostly builtin, since there is no definition for them in the system unit. Slightly different from mere inline functions.
Marco van de Voort
I'm not convinced that something can be *returned* when there is no function call happening. It is more like an *empty inline function*.
Uwe Raabe
@Uwe Raabe, indeed. But what I meant in my comment is that the expression is evaluated (if it has to be evaluated) and stored temporarily (lets say in a register) and then it can be assigned to some other variable. No value is actually returned (and no body is executed) because the temporary value can be used right away.
Nick D
@Nick D: see the example in my edited answer.
Uwe Raabe
+3  A: 

The help says: Chr returns the character with the ordinal value (ASCII value) of the byte-type expression, X. *

So, how is a character represented in a computer's memory? Guess what, as a byte*. Actually the Chr and Ord functions are only there for Pascal being a strictly typed language prohibiting the use of bytes* where characters are requested. For the computer the resulting char is still represented as byte* - to what shall it convert then? Actually there is no code emitted for this function call, just as there is no code omitted for a type cast. Ergo: no difference.

You may prefer chr just to avoid a type cast.

Note: type casts shall not be confused with explicit type conversions! In Delphi 2010 writing something like Char(a) while a is an AnsiChar, will actually do something.

*For Unicode please replace byte with integer

Edit:

Just an example to make it clear (assuming non-Unicode):

var
  a: Byte;
  c: char;
  b: Byte;
begin
  a := 60;
  c := Chr(60);
  c := Chr(a);
  b := a;
end;

produces similar code

ftest.pas.46: a := 60;
0045836D C645FB3C         mov byte ptr [ebp-$05],$3c
ftest.pas.47: c := Chr(60);
00458371 C645FA3C         mov byte ptr [ebp-$06],$3c
ftest.pas.48: c := Chr(a);
00458375 8A45FB           mov al,[ebp-$05]
00458378 8845FA           mov [ebp-$06],al
ftest.pas.49: b := a;
0045837B 8A45FB           mov al,[ebp-$05]
0045837E 8845F9           mov [ebp-$07],al

Assigning byte to byte is actually the same as assigning byte to char via CHR().

Uwe Raabe
The ORD() function works on more than characters.
Marco van de Voort
I know, the char was only an example. ORD() will also only return the internal integer representation of the given ordinal typed value. So again no actual function call here and no code emitted.
Uwe Raabe
A: 

They are identical, but they don't have to be identical. There's no requirement that the internal representation of characters map 1-to-1 with their ordinal values. Nothing says that a Char variable holding the value 'A' must hold the numeric value 65. The requirement is that when you call Ord on that variable, the result must be 65 because that's the code point designated for the letter A in your program's character encoding.

Of course, the easiest implementation of that requirement is for the variable to hold the numeric value 65 as well. Because of this, the function calls and the type-casts are always identical.

If the implementation were different, then when you called Chr(65), the compiler would go look up what character is at code point 65 and use it as the result. When you write Char(65), the compiler wouldn't worry about what character it really represents, as long as the numeric result stored in memory was 65.

Is this splitting hairs? Yes, absolutely, because in all current implementations, they're identical. I liken this to the issue of whether the null pointer is necessarily zero. It's not, but under all implementations, it ends up that way anyway.

Rob Kennedy
A: 

chr is typesafe, char isn't: Try to code chr(256) and you'll get a compiler error. Try to code char(256) and you will either get the character with the ordinal value 0 or 1, depending on your computers internal representation of integers.

I'll suffix the above by saying that that applies to pre-unicode Delphi. I don't know if chr and char have been updated to take unicode into account.

Mike Sutton
What computers use an internal representation of integers where type-casting 256 to `Char` would yield a character with ordinal value 255?
Rob Kennedy
Oops, that will teach me to post when tired. Answer corrected.
Mike Sutton