9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DelphiAdvent Calendar 2022

Day 15

Delphi 10.3以降: 列挙型で順序値を割り当てたときに起きるE2026エラーを回避する

Last updated at Posted at 2022-12-14

はじめに

Delphiの列挙型はOrd関数で順序値を返すことができます。
列挙型の定義を

type
  TEnum = (Val0 = 5, Val1 = 10, Val = 15); 

と定義すると Ord(TEnum.Val0)5 を返します。
順序値は整数型で -2147483648..2147483647 の範囲を指定できます。
順序値が指定されていない場合は0から順番に1,2,3・・・の値が設定されます。

検証

では,実際に試してみましょう。
新しいプロジェクトを新規作成し,以下のようにTButtonTMemoを配置します。
Snap0011.png
配置されたButton1にClickイベントを設定し,以下のように書きます。

unit1.pas
type
  // TEnum0 順序値を指定しない列挙型
  TEnum0 = (
    te0Val0,
    te0Val1,
    te0Val2,
    te0None
  );
  // TEnum1 順序値を指定した列挙型
  TEnum1 = (
    te1Val0 = 0,
    te1Val1 = 1,
    te1Val2 = 2,
    te1None = 2147483647 // 順序型で指定できる最大値 $7FFFFFFF
  );

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Clear;
  // TEnum0 の順序値の表示
  Memo1.Lines.Add('TEnum0.te0Val0 = '+ord(TEnum0.te0Val0).ToString);
  Memo1.Lines.Add('TEnum0.te0Val1 = '+ord(TEnum0.te0Val1).ToString);
  Memo1.Lines.Add('TEnum0.te0Val2 = '+ord(TEnum0.te0Val2).ToString);
  Memo1.Lines.Add('TEnum0.te0None = '+ord(TEnum0.te0None).ToString);
  // TEnum1 の順序値の表示
  Memo1.Lines.Add('TEnum1.te1Val0 = '+ord(TEnum1.te1Val0).ToString);
  Memo1.Lines.Add('TEnum1.te1Val1 = '+ord(TEnum1.te1Val1).ToString);
  Memo1.Lines.Add('TEnum1.te1Val2 = '+ord(TEnum1.te1Val2).ToString);
  Memo1.Lines.Add('TEnum1.te1None = '+ord(TEnum1.te1None).ToString);
end;

実行して,Button1をクリックすると,Memo1には以下のように表示されます。

TEnum0.te0Val0 = 0
TEnum0.te0Val1 = 1
TEnum0.te0Val2 = 2
TEnum0.te0None = 3
TEnum1.te1Val0 = 0
TEnum1.te1Val1 = 1
TEnum1.te1Val2 = 2
TEnum1.te1None = 2147483647

期待通りの動作です。

ここで問題

Delphi 10.2 以前のライブラリには,以下のような列挙型が定義されていることがあります。
(今手元にあるのが10.3以降ですので,以下のコードが10.2以前で動作するか確認できませんでした。)

type
  // TEnum 10.2 以前は問題なく使えたらしい列挙型
  TEnum = (
    te0Val0 = 0,
    te0Val1 = 1,
    te0Val2 = 2,
    te0None = $FFFFFFFF
  );

こう書くと,10.3以降では,

E2026 定数式が必要です 行 YYY (YYYY:XX)

と表示されて,実行できなくなります。これが今回解決したい問題です。

回避方法 ・・・ 整数型でキャストする

このエラーは 「コンパイラはここで定数式を期待しましたが,見つかった式は定数式ではありませんでした。」
というものなのですが,ちょっと違和感ありますね。定数が求められている方とは違う,あるいは,オーバーフローしているというエラーではないかと思います。

順序値は整数型なので32bitです。なので,$FFFFFFFFはサイズは収まっています。
そこで$FFFFFFFFをintegerにキャストすれば定義できるはずです。
integerが32bitであることが分かりにくいと感じるなら,INT32FixedIntでキャストすると良いと思います。
ちなみに,32bitと64bitで長さが変わる整数型はNativeIntです。

最初に書いたプログラムを書き換えてテストをしてみましょう。

unit1.pas
type
  // TEnum0 順序値を指定しない列挙型
  TEnum0 = (
    te0Val0,
    te0Val1,
    te0Val2,
    te0None
  );
  // TEnum1 順序値を指定した列挙型
  TEnum1 = (
    te1Val0 = 0,
    te1Val1 = 1,
    te1Val2 = 2,
    te1None = INT32($FFFFFFFF)  // INT32でキャスト
  );

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Clear;
  // TEnum0 の順序値の表示
  Memo1.Lines.Add('TEnum0.te0Val0 = '+ord(TEnum0.te0Val0).ToString);
  Memo1.Lines.Add('TEnum0.te0Val1 = '+ord(TEnum0.te0Val1).ToString);
  Memo1.Lines.Add('TEnum0.te0Val2 = '+ord(TEnum0.te0Val2).ToString);
  Memo1.Lines.Add('TEnum0.te0None = '+ord(TEnum0.te0None).ToString);
  // TEnum1 の順序値の表示
  Memo1.Lines.Add('TEnum1.te1Val0 = '+ord(TEnum1.te1Val0).ToString);
  Memo1.Lines.Add('TEnum1.te1Val1 = '+ord(TEnum1.te1Val1).ToString);
  Memo1.Lines.Add('TEnum1.te1Val2 = '+ord(TEnum1.te1Val2).ToString);
  Memo1.Lines.Add('TEnum1.te1None = '+ord(TEnum1.te1None).ToString); // そのままだと -1 が表示される
  // 一旦DWORDにキャストしてHEXで表示すると期待された順序値になっていることが分かる
  Memo1.Lines.Add('TEnum1.te1None= '+DWORD(ord(TEnum1.te1None)).ToHexString);
end;

実行してButton1をクリックすると,Memo1には以下のように表示されます。

TEnum0.te0Val0= 0
TEnum0.te0Val1= 1
TEnum0.te0Val2= 2
TEnum0.te0None= 3
TEnum1.te1Val0= 0
TEnum1.te1Val1= 1
TEnum1.te1Val2= 2
TEnum1.te1None= -1
TEnum1.te1None= FFFFFFFF

と,期待された値が格納されていることが分かります。Ord関数を使って直接順序値を扱う場合にはDWORDでキャストしたほうが良いかもしれません。
そのままで期待した動作にならない場合には検討されると良いと思います。また,DWORDの代わりにUINT32でキャストしても同様の効果が得られます。

まとめ

  • Delphi 10.2以前のライブラリをそれ以降のDelphiでコンパイルした時に,E2026エラーが出たら,列挙型の順序値の定義を疑ってみる。
  • 順序値が2,147,483,647($7FFFFFFF)より大きい値が指定されていたら,IntegerまたはINT32で順序値をキャストする。
    例: $FFFFFFFFinteger($FFFFFFFF)

10.2以前のライブラリの更新作業などのお役に立てば幸いです。

謝辞

以下のリンクを参考にしてこの記事を書きました。

ありがとうございます。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?