pascal類型、變量及常量


最初的Pascal 語言是以一些簡單的概念為基礎建立起來的,這些概念現在普遍出現在編程語言中。最重要的概念當屬數據類型,數據類型決定了變量可取的值,以及可在這些值上進行的操作。Pascal 數據類型的概念強於C語言及早期的BASIC語言,在C語言中算術數據類型是可以互換的,而早期的BASIC語言中根本沒有與數據類型相似的概念。

變量

Pascal 變量在使用前必須聲明,聲明變量時必須指定一種數據類型。下面是變量聲明的例子:

var
  Value: Integer;
  IsCorrect: Boolean;
  A, B: Char;

關鍵字var可以在許多地方使用,例如放在函數或過程的開始部分,用來聲明函數或過程的局部變量;也可以放在單元中,用於聲明全程變量。var關鍵字之后是一組變量名列表,每個變量名后跟一個冒號和數據類型名,一行中可以聲明多個變量,如上例中最后一句。

一旦變量的類型被指定,你只能對變量執行該變量類型支持的操作。例如,在判斷操作中用布爾值,在數字表達式中用整型值,你不能將布爾值和整型值混用(在C語言中可以這樣)。

使用簡單的賦值語句,可寫出下面的代碼:

Value := 10;
IsCorrect := True;

但下面的語句是不正確的,因為兩個變量數據類型不同:

Value := IsCorrect; // error

在Delphi中編譯這句代碼,會出現錯誤信息:Incompatible types: 'Integer' and 'Boolean'.(類型不兼容:‘整型’和‘布爾型’)。象這樣的錯誤通常是編程錯誤,因為把一個 TrueFalse 的值賦給一個整型變量沒有什么意義。你不該責怪Delphi 提示這樣的錯誤信息,代碼中有不對的地方Delphi當然要提出警告。

把變量的值從一種類型轉換到另一種類型往往不難做到,有些情況下類型轉換會自動實現,不過一般情況下需要調用特殊的系統函數,通過改變數據內部表示來實現類型轉換。

在Delphi 中,當你聲明全程變量時,你可以賦給它一個初值。例如,你可以這樣寫:

var
  Value: Integer = 10;
  Correct: Boolean = True;

這種初始化方法只能用於全程變量,不能用於過程或方法的變量。

常量

對於在程序運行期間保持不變的值,Pascal 允許通過常量來聲明。聲明常量不必特定數據類型,但需要賦一個初值。編譯器會根據所賦初值自動選用合適的數據類型。例如:

const
  Thousand = 1000;
  Pi = 3.14;
  AuthorName = 'Marco Cantù';

Delphi 根據常量的值來決定它的數據類型。上例中的Thousand 變量,Delphi會選用SmallInt數據類型 (短整型--能容納Thousand變量的最小整數類型)。如果你想告訴Delphi 采用特定的類型,你可在聲明中加入類型名,方法如下:

const
  Thousand: Integer = 1000;

對於聲名的常量,編譯器有兩種編譯選擇:第一種為常量分配內存,並把常量的值放入內存;第二種在常量每次使用時復制常量值。第二種方法比較適合簡單常量。

注意:16位的Delphi 允許你在程序運行期間改變已定義的常量值,就象一個變量一樣。32位的Delphi為了向后兼容仍容許這種操作,只要你附加 $J 編譯指令,或選擇工程選項對話框中Compiler (編譯器) 頁的Assignable typed constants復選框就行。盡管如此,這里我還是要強烈建議萬不得以不要使用上述操作,因為把新值賦給常量將使編譯器不能對常量進行優化,與其如此不如直接聲明一個變量。

資源串常量

當定義字符串常量時,你可這樣寫:

const
  AuthorName = 'Marco Cantù';

從Delphi 3 開始,你可以用另一種方式寫:

resourcestring
  AuthorName = 'Marco Cantù';

上面兩個語句都定義了一個常量,也就是定義了一個在程序運行期間保持不變的值,但兩者的實現過程卻不同,用resourcestring 指令定義的字符串變量將被保存到程序資源的字符串表中。從例子ResStr你可了解資源串的實際作用,例子中設置了一個按鈕, 相應代碼如下:

resourcestring
  AuthorName = 'Marco Cantù';
  BookName = 'Essential Pascal';

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage (BookName + #13 + AuthorName);
end;

以上代碼中的兩個字符串將分兩行輸出顯示,因為字符串被分行符 #13 隔開。

有趣的是,當你用資源編輯器打開執行文件時,你會在程序資源中看到你所定義的字符串。這意味着字符串並沒有進入編譯代碼,而是保存在執行文件 (EXE文件) 的一個單獨區域。

注意:簡而言之,采用資源的好處一方面可讓Windows 來完成有效的內存處理,另一方面不用更改源代碼就可實現程序的本地化 (把字符串翻譯成不同的語言)。

數據類型

Pascal 中有多種預定義的數據類型,它們可分為三大類:有序數據類型,實數類型和字符串類型。下面我們先討論有序類型和實數類型,字符串類型放在以后討論。同時這一節還將介紹幾種Delphi 庫中定義的類型 (不是編譯器預定義的類型),這些類型也可看作是預定義的類型。

Delphi 還包括一種無類型的可變數據類型,稱作variant,在本書的第十章將討論這一類型。variant是一種無需類型檢測的數據類型,它在Delphi 2 中引入,用於處理OLE Automation(OLE 自動化)。

有序類型

有序類型是建立在概念“順序”或“序列”基礎上的數據類型。你不僅可比較兩個有序值的大小,而且可以求取給定有序值的前驅及后繼,或者計算它們的最大或最小值。

三種最重要的預定義有序類型是整數類型、布爾類型和字符類型(Integer,Boolean,Char)。各種類型根據其內部表示和取值范圍不同又可進一步細分。表3.1列出了表示數字的有序數據類型。

表 3.1: 表示數字的有序數據類型

 

大小 有符號值域 無符號值域
8 bits ShortInt
-128 to 127
Byte
0 to 255
16 bits SmallInt
-32768 to 32767
Word
0 to 65,535
32 bits LongInt
-2,147,483,648 to 2,147,483,647
LongWord (從 Delphi 4)
0 to 4,294,967,295
64 bits Int64
16/32 bits Integer Cardinal

從表中可看到,不同數據類型與不同的數據表示法相對應,這要取決於數據值的數位和符號位。有符號類型的數值可正可負,但取值范圍較小,因為符號位占一個數位。下一節在例Range中說明了每種類型的實際取值范圍。

表中最后一組類型標志着16/32,它表明其數值表示方法在16位和32位Delphi中不同,該組的Integer及Cardinal 類型比較常用,因為它們與CPU內部的數字表示法相對應。

Delphi 4中的整數類型

在 Delphi 3中,Cardinal類型所表示的32位無符號值實際占31位,取值最高為20億。Delphi 4新增了一種無符號數字類型--LongWord,它是真正的32位值,取值最高達40億。現在Cardinal 類型已成了LongWord類型的別名,只是LongWord能容納大於20億的無符號數,而且它的數值表示法與CPU內部數值表示法一致。

Delphi 4 中新增的另一個數據類型是Int64 類型,這一類型能表示長達18個數字的整數。系統中的有序類型例程(如High 和Low)、數字例程(如Inc 和 Dec)及字符串轉換例程(如IntToStr)都支持這一新類型。反過來,有兩個新增的專用函數StrToInt64StrToInt64Def支持從字符串向數字的轉換。

布爾類型

布爾值不同於布爾類型,平時很少用到。ByteBool、 WordBool 和LongBool這三種布爾類型的布爾值比較特殊,只在Windows API 函數中才用到它們。

在Delphi 3 中,為了與Visual Basic 和 OLE Automation兼容,修改了ByteBoolWordBool LongBool的布爾值,將TRUE值設置為1,FALSE值仍為0;Boolean類型布爾值保持不變(TRUE為1,FALSE為0)。如果在Delphi 2代碼中使用了布爾值顯式類型轉換 ,那么在以后的Delphi中可能會出錯。

字符類型

字符有兩種不同的表示法:: ANSICharWideChar。第一種類型代表 8 位的字符,與Windows一直沿用的ANSI(美國國家標准協會)字符集相應;第二種類型代表 16 位的字符,與Windows NT、Windows 95 和 98支持的雙字節字符(Unicode)相應。在Delphi 3 中,Char 類型字符與ANSIChar一致。切記,不管在什么環境,前 256 個Unicode 字符與ANSI 字符是完全一致的。

常量字符可用代表它們的符號表示,如‘k’,也可用數字符號表示,如 #78。后者還可用Chr函數表示為 Chr(78),用Ord函數可作相反的轉換Ord(k)

一般來說,對字母、數字或符號,用代表它們的符號來表示較好;而涉及到特殊字符時用數字符號較好。下面列出了常用的特殊字符:

  • #9 跳格 (Tab 鍵)
  • #10 換行
  • #13 回車 (Enter 鍵)
一個例子:Range

為使你對一些有序類型的不同取值范圍有一個認識,我寫了一個名為Range 的Delphi程序簡例。結果見圖3.1。

圖3.1 簡例Range顯示有序數據類型信息(本例中采用整型)

Range 程序基於一個簡單的窗體,上面有六個按扭 (按有序數據類型命名),還有幾個標簽(Label)用於顯示信息,見圖3.1。窗體最左邊的一列標簽顯示的是靜態文本,左邊第二列標簽在每次單擊按扭時顯示數據類型信息。

每當你按一下窗體右邊的一個按鈕,程序就會更新第二列標簽的顯示內容,顯示的內容包括數據類型、字節數、該類型可存儲的最大值和最小值。每個按鈕都帶有各自的OnClick 事件,因為各自的計算代碼略有不同。例如,以下是Integer按鈕(BtnInteger)OnClick 事件的源代碼:

procedure TFormRange.BtnIntegerClick(Sender: TObject);
begin
  LabelType.Caption := 'Integer';
  LabelSize.Caption := IntToStr (SizeOf (Integer));
  LabelMax.Caption := IntToStr (High (Integer));
  LabelMin.Caption := IntToStr (Low (Integer));
end;

如果你有Delphi 編程經驗,你可以看一下程序的源代碼,弄明白程序到底是如何工作的。對於初學者,注意一下SizeOf、 High、 Low這三個函數的使用就可以了。High、 Low兩個函數返回與參數相同的有序類型(這里是整型),SizeOf 函數返回整型數據。函數的返回值先用IntToStr 函數轉成字符串,然后賦給三個標簽的caption屬性 。

其他按鈕事件與上面相似,唯一的不同點在於傳遞給函數的參數類型是不同的。圖3.2 顯示了Windows 95 下的16位Delphi編譯程序的執行結果。比較圖3.1和圖3.2,可以看出16位整型和32位整型之間的差異。

圖3.2 :16位Delphi中Range程序運行結果顯示的整型信息

整型類型的字節大小取決於你所使用的CPU和操作系統。在16位的Windows中,整型變量占兩個字節,在32位的Windows中,整型變量占4個字節。因此,在兩個環境中編譯的Range程序會得到不同的結果。

如果你的程序對整數類型的字節大小沒有特殊要求,Integer 類型在不同版本中的差異並不是個大問題。如果你在一個版本中保存了一個整數,那么在另一個版本中取出這個整數時可能會遇到一些問題,這種情況下,你應該采用平台無關的數據類型如 LongIntSmallInt。對於數學計算或非特殊的代碼中,你最好的選擇是堅持使用平台相應的標准整型,這就是說,使用CPU最喜歡的整型類型。當處理整數時,Integer 應是你的首選,不到迫不得已最好不要采用其他的整型類型。

有序類型系統例程

Pascal 語言和Delphi System 單元中定義了一系列有序類型操作例程,見表 3.2。C++ 程序員會注意到其中的Inc 例程,它可與 ++ 和 += 運算符對應(Dec 例程也同樣)。

表 3.2: 有序類型系統例程

 

例程 作用
Dec 將例程中的參數值遞減1或一個特定的值,其中特定值可在第二個可選參數中定義
Inc 將例程中的參數值增加1或一個特定的值
Odd 如果參數為奇數返回真
Pred 根據參數在其數據類型定義中的序列,返回參數值的前驅值
Succ 返回參數值的后繼值
Ord 返回參數值在其數據類型值集合中的序號
Low 返回參數對應的有序數據類型的最小取值
High 返回參數對應的有序數據類型的最大取值

注意,當有些例程用於常量時,編譯器會自動用計算值替代例程。例如你調用High(X) ,設定X為一個整數,那么編譯器會用整數類型中最大的可能值代替這個表達式。

實數類型

實數類型代表不同格式的浮點數。Single類型占的字節數最小,為4個字節;其次是Double 浮點類型,占8個字節;Extended 浮點類型,占10個字節。這些不同精度的浮點數據類型都與IEEE( 電氣和電子工程師協會)標准的浮點數表示法一致,並且 CPU數字協處理器直接支持這些類型,處理速度也最快。

Real 類型在Delphi 2 和 Delphi 3 中的定義與 16 位版本一樣,都占 6 個字節。不過Borland公司一直不提倡使用這種類型,而建議用Single、 Double、 Extended 類型代替。這是由於 Real 這種 6 字節的舊格式既不受 Intel CPU 的支持,又沒有列在官方的IEEE 實型中。為了完全解決這一問題,Delphi 4 不得不修改 Real 類型的定義,將其改成標准的 8 字節浮點型, 由此引起了兼容性問題,不過如果有必要,你可以采用下面編譯指令克服兼容性問題,恢復Delphi 2 和 Delphi 3 的Real 類型定義:

{$REALCOMPATIBILITY ON}

另外還有兩種奇怪的數據類型:Comp 類型和Currency 類型,Comp 類型用 8 個字節描述非常大的整數(這種類型可支持帶有 18 位小數的數字);Currency 類型 (16 位版的Delphi不支持該類型) 表示一個有四位小數位的值,它的小數位長度是固定的,同Comp 類型一樣也占 8 個字節。正如名字所示,Currency 數據類型是為了操作很精確的四位小數貨幣數值才添加的。

對實型數據,我們沒辦法編一個類似Range的程序,因為High 、Low及 Ord函數不能用於實型值。理論上說實型類型代表一個無限的數字集合;有序類型代表一個有限的數字集合。

注意:讓我進一步把上述問題解釋一下。對於整數 23,你能確定23 后面的數是什么 ,因為整型數是有限的,它們有確定的值域范圍及排列順序。而浮點數即使在一個很小的值域范圍內也無限、無序。 事實上,在 23 和 24 之間有多少值? 哪個值是 23.46 后面的值? 23.47 還是 23.461,或者 23.4601? 這是很難說清的。

因此,如問Char 類型字符 w 的順序位置是有意義的, 但同樣的問題對浮點類型數 7134.1562 就毫無意義。對於一個實型數,你能確切知道有沒有比它大的實型數,但是,如想探究給定的實數前到底有多少個實型數(這是Ord 函數的作用),是得不到結果的。

實型類型在用戶界面編程中用得不多,但是Delphi從各方面支持實型類型,包括在數據庫方面的支持。由於支持IEEE浮點數運算標准,Object Pascal 語言完全適合於各類數值計算編程。如果對這部分感興趣,你可以參考Delphi 在System單元中提供的算術函數(詳細見Delphi 幫助)。

注意:Delphi 帶有一個Math 單元,其中定義了一些高級數學例程,這些例程包括三角函數(如ArcCosh 函數)、金融函數(如InterestPayment 函數)和統計函數(如MeanAndStdDev 過程)。有些例程,它的名字聽起來很怪,如MomentSkewKurtosis 例程,它是作什么用的呢? 還是留你自己查吧。

日期和時間

Delphi 也用實型數表示日期和時間數據。但為了更准確起見,Delphi 特別定義了TDateTime 數據類型,這是一個浮點類型,因為這個類型必須足夠寬,使變量能容納年、月、日、時、分和秒、甚至毫秒。日期值按天計數,從1899-12-30開始,放在TDateTime 類型的整數部分;時間值則位於十進制數的小數部分。

TDateTime 不是編譯器可直接識別的預定義類型,它在System單元定義:

type
  TDateTime = type Double;

使用TDateTime 類型很簡單,因為Delphi 為該類型定義了一系列操作函數,表3.3列出了這些函數。

表3.3: TDateTime類型系統例程

 

例程 作用
Now 返回當前日期及時間
Date 返回當前日期
Time 返回當前時間
DateTimeToStr 按缺省格式將日期和時間值轉換為字符串;特定格式轉換可用 FormatDateTime函數
DateTimeToString 按缺省格式將日期和時間值拷貝到字符串緩沖區
DateToStr 將TDateTime值的日期部分轉為字符串
TimeToStr 將TDateTime值的時間部分轉為字符串
FormatDateTime 按特定格式將日期和時間值轉換為字符串
StrToDateTime 將帶有日期和時間信息的字符串轉換為TdateTime類型值,如串有誤將引發一個異常
StrToDate 將帶有日期信息的字符串轉換為TDateTime類型格式
StrToTime 將帶有時間信息的字符串轉換為TDateTime類型格式
DayOfWeek 根據傳遞的日期參數計算該日期是一星期中的第幾天
DecodeDate 根據日期值返回年、月、日值
DecodeTime 根據時間值返回時、分、秒、毫秒值
EncodeDate 組合年、月、日值為TDateTime類型值
EncodeTime 組合時、分、秒、毫秒值為TDateTime類型值

為了顯示怎樣使用日期時間類型及其相關例程,我建了一個簡單的例子TimeNow。該例子在主窗體中設置了一個按鈕和一個列表框(ListBox)。開始執行時,程序自動計算並顯示當前的時間及日期,以后每次單擊按鈕 ,顯示從程序開始至當前的時間。

下面列出了窗體的OnCreate 事件代碼:

procedure TFormTimeNow.FormCreate(Sender: TObject);
begin
  StartTime := Now;
  ListBox1.Items.Add (TimeToStr (StartTime));
  ListBox1.Items.Add (DateToStr (StartTime));
  ListBox1.Items.Add ('Press button for elapsed time');
end;

第一句中調用了Now 函數,這個函數返回當前的日期和時間,它的值保存在StartTime 變量中,StartTime 變量是全程變量,其聲明如下:

var
  FormTimeNow: TFormTimeNow;
  StartTime: TDateTime;

我只添加了第二個聲明,第一個是由Delphi自動添加的。默認情況下的代碼如下:

var
  Form1: TForm1;

窗體名改變后,這個聲明被自動更新。使用全程變量實際上不是最好的辦法,更好的方法是使用窗體類的私有域,這涉及到面向對象的編程技術。

接下來的三個語句向位於窗體左面的列表框添加三個條目,結果見圖3.3。列表框中的第一行顯示了TDateTime 值的時間部分字符串、第二行顯示的是同一值的日期部分,最后一行顯示了一個簡單的提示。

圖 3.3:例TimeNow啟動時的輸出顯示

當用戶單擊Elapsed 按鈕時,上圖第三行字符串被程序的計算結果代替:

procedure TFormTimeNow.ButtonElapsedClick(Sender: TObject);
var
  StopTime: TDateTime;
begin
  StopTime := Now;
  ListBox1.Items [2] :=  FormatDateTime ('hh:nn:ss',
    StopTime - StartTime);
end;

這串代碼再次計算當前的時間,並顯示當前與程序開始之時的時間差,其中用到了其它事件中的計算值,為此不得不把該值存入全程變量。實際上,最好是采用基於類的變量。

注意:上面代碼中所用ListBox的索引號為2,,而它代表的是第三行的顯示輸出,其原因是listbox的數據項是從零開始計數的:第一項計為0,第二項為1,第三項為2,依次類推,后面涉及數組時再詳細討論這方面內容。

除了調用TimeToStr和 DateToStr 外,以上例子中還用到了功能強大的FormatDateTime 函數(關於格式化參數詳見Delphi 幫助文件)。需要注意的是:當時間和日期轉換成字符串時,其轉換格式取決於Windows 的系統設置。Delphi 從系統中讀這些值,並把它們拷貝到SysUtils 單元中聲明的幾個全程常量中,例如:

DateSeparator: Char;
ShortDateFormat: string;
LongDateFormat: string;
TimeSeparator: Char;
TimeAMString: string;
TimePMString: string;
ShortTimeFormat: string;
LongTimeFormat: string;
ShortMonthNames: array [1..12] of string;
LongMonthNames: array [1..12] of string;
ShortDayNames: array [1..7] of string;
LongDayNames: array [1..7] of string;

大部分全程常量與currency 和浮點數格式化有關,在 Delphi 幫助的 Currency and date/time formatting variables 主題下,你可找到完整的清單。

注意:Delphi 中有一個DateTimePicker 控件,它提供了選擇日期的常用途徑,即從一個日歷中選擇日期。

特定的Windows 類型

到目前為止,我們所看到的預定義數據類型都是Pascal 語言自身定義的類型。 Delphi 中還包含Windows系統定義的數據類型,這些數據類型不是Pascal語言的組成部分,而是Windows 庫的一部分。Windows 類型包括新增的缺省類型(例如DWORD 或UINT)、各種記錄(或結構)類型及指針類型等。

Windows 定義的數據類型中,最重要的類型是句柄(handle),第九章中將討論這一類型。

類型映射及類型轉換

正如所知,你不能把一個變量賦給另一個不同類型的變量,如果你需要這么做,有兩種方法供選擇。第一種方法是采用類型映射(Typecasting),它使用一個帶有目標數據類型名的函數符號:

var
  N: Integer;
  C: Char;
  B: Boolean;
begin
  N := Integer ('X');
  C := Char (N);
  B := Boolean (0);

你可以在字節長度相同的數據類型之間進行類型映射。在有序類型之間或實型數據之間進行類型映射通常是安全的,指針類型及對象之間也可以進行類型映射 ,只要你明白自己在做什么。

然而,一般來說類型映射是一種較危險的編程技術,因為它允許你訪問一個似是而非的值,該值好象是其它值的替身。由於數據類型的內部表示法之間通常互相不匹配,所以當遇到錯誤時會難以追蹤,為此你應盡量避免使用類型映射。

第二種方法是使用類型轉換例程。表3.4中總結了各種類型轉換例程。其中有些例程所涉及的數據類型將在下一節中討論。 注意表中沒有包括特殊類型(如TDateTime 和variant)的轉換例程,也沒包括用於格式化處理的特殊例程,如FormatFormatFloat 例程。

表3.4:類型轉換系統例程

 

例程 作用
Chr 將一個有序數據轉換為一個ANSI字符
Ord 將一個有序類型值轉換為它的序號
Round 轉換一個實型值為四舍五入后的整型值
Trunc 轉換一個實型值為小數截斷后的整型值
Int 返回浮點數的整數部分
IntToStr 將數值轉換為字符串
IntToHex 將數值轉換為十六進制數字符串
StrToInt 將字符串轉換為一個整型數,如字符串不是一個合法的整型將引發異常
StrToIntDef 將字符串轉換為一個整數,如字符串不合法返回一個缺省值
Val 將字符串轉換為一個數字(傳統Turbo Pascal例程用於向后兼容)
Str 將數字轉換為格式化字符串(傳統Turbo Pascal例程用於向后兼容)
StrPas 將零終止字符串轉換為Pascal類型字符串,在32位Delphi中這種類型轉換是自動進行的
StrPCopy 拷貝一個Pascal類型字符串到一個零終止字符串, 在32位Delphi中這種類型轉換是自動進行的
StrPLCopy 拷貝Pascal類型字符串的一部分到一個零終止字符串
FloatToDecimal 將一個浮點數轉換為包含指數、數字及符號的十進制浮點記錄類型
FloatToStr 將浮點值轉換為缺省格式的字符串
FloatToStrF 將浮點值轉換為特定格式的字符串
FloatToText 使用特定格式,將一個浮點值拷貝到一個字符串緩沖區
FloatToTextFmt 同上面例程,使用特定格式,將一個浮點值拷貝到一個字符串緩沖區
StrToFloat 將一個Pascal字符串轉換為浮點數
TextToFloat 將一個零終止字符串轉換為浮點數

注意:在最近版本的Delphi Pascal 編譯器中,Round 函數是以 CPU 的 FPU (浮點部件) 處理器為基礎的。這種處理器采用了所謂的 "銀行家舍入法",即對中間值 (如 5.5、6.5) 實施Round函數時,處理器根據小數點前數字的奇、偶性來確定舍入與否,如 5.5 Round 結果為 6,而 6.5 Round 結果也為6, 因為 6 是偶數。

結束語

本章討論了Pascal的基本數據類型。Pascal語言還有一個非常重要的特征:它允許編程者自定義數據類型,稱為“用戶自定義數據類型”,這在下一章進行討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM