Dlaczego tak często wpisujemy strukturę w C?

Widziałem wiele programów składających się ze struktur takich jak ten poniżej

typedef struct 
{
    int i;
    char k;
} elem;

elem user;
Dlaczego jest to tak często potrzebne? Jakiś konkretny powód lub obszar?
Author: nbro, 2008-10-31

15 answers

Jak powiedział Greg Hewgill, typedef oznacza, że nie musisz już pisać struct wszędzie. To nie tylko oszczędza naciśnięcia klawiszy, ale także może uczynić kod czystszym, ponieważ zapewnia odrobinę więcej abstrakcji.

Rzeczy jak

typedef struct {
  int x, y;
} Point;

Point point_new(int x, int y)
{
  Point a;
  a.x = x;
  a.y = y;
  return a;
}

Staje się czystsze, gdy nie musisz widzieć słowa kluczowego "struct" wszędzie, wygląda to bardziej tak, jakby w Twoim języku naprawdę istniał Typ o nazwie "Point". Co, po typedef, chyba tak.

Zauważ również, że podczas gdy twój przykład (i mój) pominięto nazwanie samego struct, w rzeczywistości nazwanie jest również przydatne, gdy chcesz podać nieprzezroczysty Typ. Wtedy w nagłówku miałbyś taki kod, na przykład:

typedef struct Point Point;

Point * point_new(int x, int y);

, a następnie podać struct deklarację w pliku implementacji:

struct Point
{
  int x, y;
};

Point * point_new(int x, int y)
{
  Point *p;
  if((p = malloc(sizeof *p)) != NULL)
  {
    p->x = x;
    p->y = y;
  }
  return p;
}

W tym drugim przypadku nie można zwrócić wartości Point by, ponieważ jej deklaracja jest ukryta przed użytkownikami pliku nagłówkowego. Jest to technika szeroko stosowana w GTK+, dla przykład.

UPDATE zauważ, że istnieją również wysoko cenione projekty C, w których użycie {[4] } do ukrycia struct jest uważane za zły pomysł, jądro Linuksa jest prawdopodobnie najbardziej znanym takim projektem. Zobacz Rozdział 5 dokumentu CodingStyle Jądra Linusa dla gniewnych słów Linusa. :) Chodzi mi o to, że "powinno" w pytaniu być może jednak nie jest osadzone w kamieniu.

 385
Author: unwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-01 23:37:20

To niesamowite, jak wielu ludzi się myli. Proszę nie wpisywać struktur w C, niepotrzebnie zanieczyszcza globalną przestrzeń nazw, która jest zazwyczaj bardzo zanieczyszczona już w dużych programach C.

Również struktury typedef ' D bez nazwy znacznika są główną przyczyną niepotrzebnego narzucania relacji porządkowych między plikami nagłówkowymi.

Rozważmy:

#ifndef FOO_H
#define FOO_H 1

#define FOO_DEF (0xDEADBABE)

struct bar; /* forward declaration, defined in bar.h*/

struct foo {
  struct bar *bar;
};

#endif

Z taką definicją, nie używając typedefów, możliwe jest, aby jednostka compland obejmowała foo.h to get at the FOO_DEF definicja. Jeśli nie spróbuje dereferencji członka 'bar' struktury foo, nie będzie potrzeby dołączania "bar".plik H.

Ponadto, ponieważ przestrzenie nazw różnią się między nazwami znaczników i nazwami członków, możliwe jest napisanie bardzo czytelnego kodu, takiego jak:

struct foo *foo;

printf("foo->bar = %p", foo->bar);

Ponieważ przestrzenie nazw są oddzielne, nie ma konfliktu w nazewnictwie zmiennych pokrywających się z ich nazwą znacznika struct.

Jeśli będę musiał zachować Twój kod, usunę Twój typedef ' d struktury.

 180
Author: Jerry Hicks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-28 23:32:45

Ze starego artykułu dana Saksa ( http://www.ddj.com/cpp/184403396?pgno=3):


Zasady nazewnictwa języka C struktury są trochę ekscentryczne, ale są całkiem nieszkodliwe. Jednakże, gdy rozszerzony na klasy w C++, te same Zasady otwierają małe pęknięcia na błędy do czołgaj się.

W C, Nazwa s pojawiająca się w

struct s
    {
    ...
    };

Jest tagiem. Nazwa znacznika nie jest typem nazwisko. Biorąc pod uwagę powyższą definicję, deklaracje takie as

s x;    /* error in C */
s *p;   /* error in C */

Są błędy w C. musisz je napisać as

struct s x;     /* OK */
struct s *p;    /* OK */

Nazwy związków i wyliczeń są również znacznikami, a nie typami.

W C znaczniki różnią się od wszystkich innych nazwy (dla funkcji, typów, zmiennych i stałych wyliczeniowych). Kompilatory C zachowują znaczniki w symbolu tabela, która jest pojęciowa, jeśli nie fizycznie oddzielony od tabeli to ma wszystkie inne nazwiska. Tak więc, to jest możliwe, aby program w C miał zarówno znacznik jak i inna nazwa z ta sama pisownia w tym samym zakresie. Na przykład,

struct s s;

Jest ważną deklaracją, która deklaruje zmienna S typu struct s. może nie jest dobrą praktyką, ale kompilatory C muszę to zaakceptować. Nigdy nie widziałem uzasadnienie dlaczego C został zaprojektowany ten sposób. Zawsze myślałem, że to błąd, ale jest.

Wielu programistów (w tym Twój naprawdę) wolą myśleć o nazwach struct jako nazwy typu, więc definiują alias na tag using a typedef. Na przykład, definiowanie

struct s
    {
    ...
    };
typedef struct s S;

Pozwala na użycie s zamiast struktury S, jak w

S x;
S *p;

Program nie może używać S jako nazwy zarówno typ jak i zmienna (lub funkcja lub stała wyliczenia):

S S;    // error
To jest dobre.

Nazwa znacznika w strukturze, Unii lub definicja enum jest opcjonalna. Wiele Programiści składają definicję struct do typedef i zrezygnować z tagów, jako in:

typedef struct
    {
    ...
    } S;

Linkowany artykuł zawiera również dyskusję na temat tego, w jaki sposób zachowanie C++ nie wymagającego typedef może powodować subtelne problemy z ukrywaniem nazw. Aby zapobiec tym problemom, dobrym pomysłem jest typedef Twoje klasy i struktury również w C++, mimo że na pierwszy rzut oka wydaje się to niepotrzebne. W C++, z typedef ukrywanie nazwy staje się błędem, o którym kompilator mówi, a nie ukrytym źródłem potencjalnych problemów.

 120
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-09 20:09:03

Użycie typedef pozwala uniknąć konieczności zapisywania struct za każdym razem, gdy deklarujesz zmienną tego typu:

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct
 52
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-31 07:16:58

Jeszcze jeden dobry powód, aby zawsze wpisywać enums i structs wynika z tego problemu:

enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};

struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;

Zauważ literówkę w EnumDef w struct (Enu u mDef)? Kompiluje się to bez błędu (lub ostrzeżenia) i jest (w zależności od dosłownej interpretacji standardu C) poprawne. Problem polega na tym, że właśnie stworzyłem nową (pustą) definicję wyliczenia w mojej strukturze. Nie używam (zgodnie z zamierzeniami) poprzedniej definicji EnumDef.

Z typdef podobny rodzaj literówek wywołały błędy kompilatora w używaniu nieznanego typu:

typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */

Opowiadałbym się za tym, aby zawsze wpisywać struktury i wyliczenia.

Nie tylko po to, aby zapisać jakieś typowanie (nie zamierzony kalambur ;)), ale dlatego, że jest bezpieczniejsze.

 35
Author: cschol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-14 22:14:34

Styl kodowania jądra Linuksa Rozdział 5 daje wielkie plusy i minusy (głównie minusy) używania typedef.

Proszę nie używać takich rzeczy jak "vps_t".

Błędemjest używanie typedef dla struktur i wskaźników. Kiedy widzisz

vps_t a;

W źródle, co to znaczy?

Natomiast, jeśli mówi

struct virtual_container *a;
Możesz powiedzieć, co to jest "a".

Wiele osób uważa, że typedefs "pomaga czytelność". Nie. Są one przydatne tylko dla:

(A) całkowicie nieprzezroczyste obiekty (gdzie typedef jest aktywnie używany do ukrycia czym jest obiekt).

Przykład: "pte_t" itd. nieprzezroczyste obiekty, do których można uzyskać dostęp tylko za pomocą odpowiednich funkcji accessora.

Uwaga! Nieprzezroczystość i "funkcje dostępu" same w sobie nie są dobre. Powód, dla którego mamy je dla takich rzeczy jak pte_t itp. czy naprawdę jest tam absolutnie zero przenośnie dostępnej informacji.

(b) Wyczyść typy całkowite, gdzie abstrakcja pomaga uniknąć nieporozumień, czy jest " int " czy "long".

U8/u16 / u32 są perfekcyjnie pisane, chociaż pasują do kategorii (d) lepiej niż tutaj.

Uwaga! Ponownie-musi być } powód do tego. Jeśli coś jest "unsigned long", to nie ma powodu, aby robić

typedef unsigned long myflags_t;

Ale jeśli istnieje wyraźny powód, dla którego w pewnych okolicznościach może być "unsigned int" i pod inne konfiguracje mogą być "unsigned long", a następnie użyj typedef.

(c) gdy używasz sparse, aby dosłownie utworzyć nowy typ do sprawdzania typu.

D) Nowe typy, które są identyczne ze standardowymi typami C99, w pewnych wyjątkowych okolicznościach.

Chociaż oczy i mózg przyzwyczaiłyby się do standardowych typów, takich jak 'uint32_t', niektórzy ludzie i tak sprzeciwiają się ich użyciu.

Dlatego dozwolone są specyficzne dla Linuksa typy 'u8/u16/u32/u64' i ich podpisane odpowiedniki, które są identyczne z typami standardowymi -- chociaż nie są one obowiązkowe w nowym kodzie twojego własnego.

Podczas edycji istniejącego kodu, który już używa jednego lub drugiego zestawu typów, należy dostosować się do istniejących wyborów w tym kodzie.

(e) typy bezpieczne do użycia w przestrzeni użytkownika.

W niektórych strukturach, które są widoczne dla przestrzeni użytkownika, nie możemy wymagać C99 typy i nie można użyć powyższego formularza "u32". Tak więc, używamy _ _ u32 i podobnych typów we wszystkich strukturach, które są współdzielone z przestrzenią użytkownika.

Może są też inne przypadki, ale zasadą powinno być, aby nigdy nie używać typedef, chyba że można wyraźnie dopasować jedną z tych zasad.

Ogólnie rzecz biorąc, wskaźnik lub struktura zawierająca elementy, do których można uzyskać bezpośredni dostęp, nie powinnynigdy być typedef.

 27
Author: Yu Hao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-27 13:27:11

Nie sądzę, aby deklaracje forward były nawet możliwe z typedef. Użycie struct, enum i union pozwala na przekazywanie deklaracji, gdy zależności (knows about) są dwukierunkowe.

Style: Użycie typedef w C++ ma całkiem sens. Może to być prawie konieczne, gdy mamy do czynienia z szablonami, które wymagają wielu i / lub zmiennych parametrów. Typedef pomaga utrzymać proste nazewnictwo.

Nie tak w języku programowania C. Użycie typedef najczęściej nie służy celu, ale aby zaciemnić wykorzystanie struktury danych. Ponieważ tylko { struct (6), enum (4), union (5)} Liczba naciśnięć klawiszy jest używana do deklarowania typu danych, nie ma prawie żadnego zastosowania do aliasingu struktury. Czy ten typ danych to union czy struct? Korzystanie z prostej deklaracji non-typdefed pozwala od razu wiedzieć, jaki to typ.

Zauważ jak Linuks jest pisany ze ścisłym unikaniem tego nonsensu aliasingowego, który przynosi typedef. Rezultatem jest minimalistyczny i czysty styl.

 10
Author: natersoz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-29 18:52:10

Okazuje się, że są za i przeciw. Użytecznym źródłem informacji jest książka "Expert C Programming" (Rozdział 3). Krótko mówiąc, w C masz wiele przestrzeni nazw: tagi, typy, nazwy członków i identyfikatory . typedef wprowadza alias dla typu i lokalizuje go w przestrzeni nazw znaczników. Mianowicie,

typedef struct Tag{
...members...
}Type;

Definiuje dwie rzeczy. Jeden znacznik w przestrzeni nazw znaczników i jeden typ w przestrzeni nazw typu. Więc możesz robić zarówno Type myType, jak i struct Tag myTagType. Deklaracje typu struct Type myType lub Tag myTagType są nielegalne. Ponadto w deklaracji takiej jak ta:

typedef Type *Type_ptr;

Definiujemy wskaźnik do naszego typu. Więc jeśli zadeklarujemy:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

Wtedy var1,var2 i myTagType1 są wskaźnikami do typu, ale myTagType2 nie.

W powyższej książce wspomniano, że struktury typedefing nie są zbyt użyteczne, ponieważ tylko chronią programistę przed napisaniem słowa struct. Mam jednak sprzeciw, podobnie jak wielu innych programistów C. Chociaż czasami okazuje się, że niektóre nazwy (dlatego nie jest to wskazane w dużych bazach kodu, takich jak jądro) jeśli chcesz zaimplementować polimorfizm w C to bardzo pomaga zajrzyj tutaj po szczegóły . Przykład:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

Możesz zrobić:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

Więc możesz uzyskać dostęp do zewnętrznego elementu (flags) poprzez wewnętrzną strukturę (MyPipe) poprzez casting. Dla mnie mniej mylące jest rzucanie całego typu niż robienie (struct MyWriter_ *) s; za każdym razem, gdy chcesz wykonać taką funkcjonalność. W takich przypadkach krótkie odnoszenie się jest wielką sprawą, zwłaszcza jeśli mocno wykorzystaj technikę w swoim kodzie.

Wreszcie, ostatnim aspektem z typami typedef ed jest niemożność ich rozszerzenia, w przeciwieństwie do makr. Jeśli na przykład masz:

#define X char[10] or
typedef char Y[10]

Możesz wtedy zadeklarować

unsigned X x; but not
unsigned Y y;

Tak naprawdę nie dbamy o to w przypadku struktur, ponieważ nie dotyczy to specyfikacji storage (volatile i const).

 9
Author: user1533288,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-29 13:59:30

Nazwa, którą (opcjonalnie) nadajesz struct, nazywa się tag name i, jak zauważono, nie jest typem samym w sobie. Aby przejść do typu, należy użyć przedrostka struct.

GTK+ pomijając, nie jestem pewien, czy tagname jest używane tak często jak typedef do typu struct, więc w C++, który jest rozpoznawany i można pominąć słowo kluczowe struct i użyć tagname jako nazwy typu również:


    struct MyStruct
    {
      int i;
    };

    // The following is legal in C++:
    MyStruct obj;
    obj.i = 7;

 3
Author: philsquared,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-31 08:24:40

Zacznijmy od podstaw i popracujmy nad sobą.

Oto przykład definicji struktury:

struct point
  {
    int x, y;
  };

Tutaj nazwa {[4] } jest opcjonalna.

Struktura może być zadeklarowana podczas jej definicji lub po jej zakończeniu.

Deklarowanie podczas definicji

struct point
  {
    int x, y;
  } first_point, second_point;

Deklarowanie po definicji

struct point
  {
    int x, y;
  };
struct point first_point, second_point;

Teraz zwróć uwagę na ostatni przypadek powyżej; musisz napisać struct point, aby zadeklarować struktury tego typu, jeśli zdecydujesz się utworzyć ten typ w późniejszym momencie w swoim kod.

Wpisz typedef. Jeśli zamierzasz utworzyć nową strukturę (struktura jest niestandardowym typem danych) w późniejszym czasie w programie, używając tego samego schematu, użycie typedef podczas jego definiowania może być dobrym pomysłem, ponieważ możesz zapisać kilka wpisów do przodu.

typedef struct point
  {
    int x, y;
  } Points;

Points first_point, second_point;

Słowo ostrożności podczas nazywania niestandardowego typu

Nic nie uniemożliwia używania sufiksu _t na końcu nazwy niestandardowego typu, ale standard POSIX zastrzega użycie sufiksu _t do oznaczenia biblioteki standardowej wpisz nazwy.

 3
Author: Asif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-29 13:42:15

Typedef nie dostarczy współzależnego zestawu struktur danych. Tego nie można zrobić z typdef:

struct bar;
struct foo;

struct foo {
    struct bar *b;
};

struct bar {
    struct foo *f;
};

Oczywiście zawsze możesz dodać:

typedef struct foo foo_t;
typedef struct bar bar_t;
Jaki w tym sens?
 1
Author: natersoz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-30 15:47:18

A> typdef pomaga w znaczeniu i dokumentacji programu, umożliwiając tworzenie bardziej znaczących synonimów dla typów danych. Ponadto pomagają one parametryzować program przed problemami z przenośnością (K & R, pg147, C prog lang).

B> Struktura definiuje typ . Structs umożliwia wygodne grupowanie kolekcji var dla wygody obsługi (K& R, pg127, C prog lang.) jako pojedyncza jednostka

C> typedef ' ing a struct jest wyjaśnione w powyżej.

D > Dla mnie struktury są typami niestandardowymi, kontenerami, kolekcjami, przestrzeniami nazw lub typami złożonymi, podczas gdy typdef jest tylko sposobem na tworzenie większej liczby nicknames.

 1
Author: JamesAD-0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-05 00:19:12

Okazuje się, że w C99 wymagany jest typedef. Jest przestarzały, ale wiele narzędzi (ala HackRank) używa c99 jako czystej implementacji C. I tam wymagany jest typedef.

Nie twierdzę, że powinny się zmienić (może mieć dwie opcje C) jeśli wymóg się zmieni, to ci z nas, którzy szukają wywiadów na stronie, będą SOL.

 0
Author: Matthew Corey Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-02 09:34:21

W języku programowania' C 'słowo kluczowe 'typedef' jest używane do deklarowania nowej nazwy jakiegoś obiektu (struct, array, function..enum type). Na przykład użyję 'struct-s'. W 'C' często deklarujemy 'struct ' poza' główną ' funkcją. Na przykład:

struct complex{ int real_part, img_part }COMPLEX;

main(){

 struct KOMPLEKS number; // number type is now a struct type
 number.real_part = 3;
 number.img_part = -1;
 printf("Number: %d.%d i \n",number.real_part, number.img_part);

}

Za każdym razem, gdy zdecyduję się użyć typu struct, będę potrzebował tego słowa kluczowego 'struct' coś ''nazwa'.'typedef' po prostu zmieni nazwę tego typu i mogę używać tej nowej nazwy w moim programie za każdym razem, gdy chcę. Więc nasz kod będzie be:

typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.

main(){

COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);

}

Jeśli masz jakiś lokalny obiekt (struct, array, valuable), który będzie używany w całym programie, możesz po prostu nadać mu nazwę używając 'typedef'.

 0
Author: RichardGeerify,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-29 13:34:44

W ogóle, w języku C, struct / union / enum są instrukcjami makr przetwarzanymi przez preprocesor języka C (nie należy mylić z preprocesorem, który traktuje "#include" i inne)

Więc:

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

Struktura B jest rozwijana w następujący sposób:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

I tak w czasie kompilacji rozwija się na stosie jako coś w rodzaju: b: int ai int i int j

Dlatego też trudno jest mieć samoistne struktury, C preprocesor Okrągły w pętli, która nie może zakończyć.

Typedef są specyfikatorami typów, co oznacza, że kompilator C przetwarza je i może zrobić tak, jak chce, aby zoptymalizować implementację kodu asemblera. Nie używa również członu typu par, podobnie jak préprocessor ze strukturami, ale używa bardziej skomplikowanego algorytmu budowy odniesienia, więc konstrukcja typu:

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

Jest dozwolone i w pełni funkcjonalne. Ta implementacja daje również dostęp do konwersji typu kompilatora i usuwa niektóre efekty podsłuchu, gdy wątek wykonania opuści pole aplikacji funkcji inicjalizacji.

Oznacza to, że w C typedefs są bardziej zbliżone do klasy C++ niż samotne struktury.

 -1
Author: doccpu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-06 14:54:22