struct and union alignment

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Richard Bos

    #46
    Re: struct and union alignment

    pete <pfiland@mindsp ring.com> wrote:
    [color=blue]
    > S.Tobias wrote:
    >[color=green]
    > > And yes, I think char type can have alignment issues. Consider this
    > > setup: Type char is composed of 4 octets.[/color]
    >
    > What are you talking about?
    > sizeof(char) is one, always.[/color]

    So? Byte != octet.

    Richard

    Comment

    • pete

      #47
      Re: struct and union alignment

      S.Tobias wrote:[color=blue]
      >
      > pete <pfiland@mindsp ring.com> wrote:[color=green]
      > > S.Tobias wrote:[color=darkred]
      > > > pete <pfiland@mindsp ring.com> wrote:
      > > > > S.Tobias wrote:
      > > > >
      > > > > > Since void* does not point to any object, is a "free pointer",
      > > > > > the Standard must specify that the void* values which are valid
      > > > > > for char*, are also valid for void*, otherwise undefined. And
      > > > > > this is what a programmer must be concerned about.
      > > >
      > > > > void* can hold the address of any byte of any object,
      > > > > just like char*.
      > > >
      > > > And which address void* in my example implementation cannot hold?[/color][/color]
      >[color=green]
      > > I don't understand your question.[/color]
      >
      > I asked because I didn't understand where to apply your statement to.
      > Perhaps, never mind.
      >[color=green][color=darkred]
      > > > > N869
      > > > > 6.3.2.3 Pointers
      > > > > [#1] A pointer to void may be converted to or from a pointer
      > > > > to any incomplete or object type. A pointer to any
      > > > > incomplete or object type may be converted to a pointer to
      > > > > void and back again; the result shall compare equal to the
      > > > > original pointer.[/color][/color]
      >[color=green][color=darkred]
      > > > Similarly, when you convert, say, an int* to void*, how do you know
      > > > that the result fulfills alignment requirements?[/color][/color]
      >[color=green]
      > > The standard says so.[/color]
      >
      > Where?
      >[color=green]
      > > You must be reading 6.3.2.3 differently from the way that I read it.[/color]
      >
      > I think that the difference between our reading of 6.3.2.3 may be
      > that you might assume that #1 demands that conversions to and from
      > void* must always succede. IMO if that were the case, then all
      > conversions from void* to unaligned int*
      > would have to complete
      > without a cough. I think this is not what the Standard requires.[/color]

      If you have an unaligned int*, then you are invoking
      undefined behavior and you code is no longer C code.
      The rules don't apply after that.
      [color=blue]
      > (In fact, I don't see why #1 is even neccessary.[/color]

      That doesn't prove that you don't understand it, but it's a clue.

      --
      pete

      Comment

      • S.Tobias

        #48
        Re: struct and union alignment

        pete <pfiland@mindsp ring.com> wrote:[color=blue]
        > S.Tobias wrote:[/color]
        [color=blue][color=green]
        > > I think that the difference between our reading of 6.3.2.3 may be
        > > that you might assume that #1 demands that conversions to and from
        > > void* must always succede. IMO if that were the case, then all
        > > conversions from void* to unaligned int*
        > > would have to complete
        > > without a cough. I think this is not what the Standard requires.[/color][/color]
        [color=blue]
        > If you have an unaligned int*, then you are invoking
        > undefined behavior and you code is no longer C code.
        > The rules don't apply after that.[/color]

        int *ip;
        char *cp;
        void *vp;

        cp = malloc(2 * sizeof(int));
        cp++; //defined
        vp = cp; //defined
        ip = vp; //???
        [color=blue][color=green]
        > > (In fact, I don't see why #1 is even neccessary.[/color][/color]
        [color=blue]
        > That doesn't prove that you don't understand it, but it's a clue.[/color]

        Maybe I don't. Would you, please, care to explain it to me.

        --
        Stan Tobias
        sed 's/[A-Z]//g' to email

        Comment

        • pete

          #49
          Re: struct and union alignment

          S.Tobias wrote:[color=blue]
          >
          > pete <pfiland@mindsp ring.com> wrote:[color=green]
          > > S.Tobias wrote:[/color]
          >[color=green][color=darkred]
          > > > I think that the difference between our reading of 6.3.2.3 may be
          > > > that you might assume that #1 demands that conversions to and from
          > > > void* must always succede. IMO if that were the case, then all
          > > > conversions from void* to unaligned int*
          > > > would have to complete
          > > > without a cough. I think this is not what the Standard requires.[/color][/color]
          >[color=green]
          > > If you have an unaligned int*, then you are invoking
          > > undefined behavior and you code is no longer C code.
          > > The rules don't apply after that.[/color]
          >
          > int *ip;
          > char *cp;
          > void *vp;
          >
          > cp = malloc(2 * sizeof(int));
          > cp++; //defined
          > vp = cp; //defined
          > ip = vp; //???[/color]

          Assuming that sizeof(int) is greater than one,
          ip = vp;
          is not defined.

          --
          pete

          Comment

          • S.Tobias

            #50
            Re: struct and union alignment

            pete <pfiland@mindsp ring.com> wrote:[color=blue]
            > S.Tobias wrote:[color=green]
            > >
            > > int *ip;
            > > char *cp;
            > > void *vp;
            > >
            > > cp = malloc(2 * sizeof(int));
            > > cp++; //defined
            > > vp = cp; //defined
            > > ip = vp; //???[/color][/color]
            [color=blue]
            > Assuming that sizeof(int) is greater than one,
            > ip = vp;
            > is not defined.[/color]

            Why?

            --
            Stan Tobias
            sed 's/[A-Z]//g' to email

            Comment

            • pete

              #51
              Re: struct and union alignment

              S.Tobias wrote:[color=blue]
              >
              > pete <pfiland@mindsp ring.com> wrote:[color=green]
              > > S.Tobias wrote:[color=darkred]
              > > >
              > > > int *ip;
              > > > char *cp;
              > > > void *vp;
              > > >
              > > > cp = malloc(2 * sizeof(int));
              > > > cp++; //defined
              > > > vp = cp; //defined
              > > > ip = vp; //???[/color][/color]
              >[color=green]
              > > Assuming that sizeof(int) is greater than one,
              > > ip = vp;
              > > is not defined.[/color]
              >
              > Why?[/color]

              Because vp holds an address which is not aligned for type int.

              --
              pete

              Comment

              • S.Tobias

                #52
                Re: struct and union alignment

                pete <pfiland@mindsp ring.com> wrote:[color=blue]
                > S.Tobias wrote:[color=green]
                > >
                > > pete <pfiland@mindsp ring.com> wrote:[color=darkred]
                > > > S.Tobias wrote:
                > > > >
                > > > > int *ip;
                > > > > char *cp;
                > > > > void *vp;
                > > > >
                > > > > cp = malloc(2 * sizeof(int));
                > > > > cp++; //defined
                > > > > vp = cp; //defined
                > > > > ip = vp; //???[/color]
                > >[color=darkred]
                > > > Assuming that sizeof(int) is greater than one,
                > > > ip = vp;
                > > > is not defined.[/color]
                > >
                > > Why?[/color][/color]
                [color=blue]
                > Because vp holds an address which is not aligned for type int.[/color]

                Which point in the Std did you apply to explain this?

                --
                Stan Tobias
                sed 's/[A-Z]//g' to email

                Comment

                • pete

                  #53
                  Re: struct and union alignment

                  S.Tobias wrote:[color=blue]
                  >
                  > pete <pfiland@mindsp ring.com> wrote:[color=green]
                  > > S.Tobias wrote:[color=darkred]
                  > > >
                  > > > pete <pfiland@mindsp ring.com> wrote:
                  > > > > S.Tobias wrote:
                  > > > > >
                  > > > > > int *ip;
                  > > > > > char *cp;
                  > > > > > void *vp;
                  > > > > >
                  > > > > > cp = malloc(2 * sizeof(int));
                  > > > > > cp++; //defined
                  > > > > > vp = cp; //defined
                  > > > > > ip = vp; //???
                  > > >
                  > > > > Assuming that sizeof(int) is greater than one,
                  > > > > ip = vp;
                  > > > > is not defined.
                  > > >
                  > > > Why?[/color][/color]
                  >[color=green]
                  > > Because vp holds an address which is not aligned for type int.[/color]
                  >
                  > Which point in the Std did you apply to explain this?[/color]

                  It would be from C89
                  C89 Last public draft

                  3.3.4 Cast operators

                  A pointer to an object or incomplete type may be converted to a
                  pointer to a different object type or a different incomplete type.
                  The resulting pointer might not be valid if it is improperly
                  aligned for the type pointed to.

                  --
                  pete

                  Comment

                  • pete

                    #54
                    Re: struct and union alignment

                    pete wrote:[color=blue]
                    >
                    > S.Tobias wrote:[color=green]
                    > >
                    > > pete <pfiland@mindsp ring.com> wrote:[color=darkred]
                    > > > S.Tobias wrote:
                    > > > >
                    > > > > pete <pfiland@mindsp ring.com> wrote:
                    > > > > > S.Tobias wrote:
                    > > > > > >
                    > > > > > > int *ip;
                    > > > > > > char *cp;
                    > > > > > > void *vp;
                    > > > > > >
                    > > > > > > cp = malloc(2 * sizeof(int));
                    > > > > > > cp++; //defined
                    > > > > > > vp = cp; //defined
                    > > > > > > ip = vp; //???
                    > > > >
                    > > > > > Assuming that sizeof(int) is greater than one,
                    > > > > > ip = vp;
                    > > > > > is not defined.
                    > > > >
                    > > > > Why?[/color]
                    > >[color=darkred]
                    > > > Because vp holds an address which is not aligned for type int.[/color]
                    > >
                    > > Which point in the Std did you apply to explain this?[/color]
                    >
                    > It would be from C89
                    > C89 Last public draft
                    >
                    > 3.3.4 Cast operators
                    >
                    > A pointer to an object or incomplete type may be converted to a
                    > pointer to a different object type or a different incomplete type.
                    > The resulting pointer might not be valid if it is improperly
                    > aligned for the type pointed to.[/color]

                    N869
                    6.3.2.3 Pointers
                    [#7] A pointer to an object or incomplete type may be
                    converted to a pointer to a different object or incomplete
                    type. If the resulting pointer is not correctly aligned
                    for the pointed-to type, the behavior is undefined.

                    --
                    pete

                    Comment

                    • S.Tobias

                      #55
                      Re: struct and union alignment

                      pete <pfiland@mindsp ring.com> wrote:[color=blue]
                      > pete wrote:[color=green]
                      > >
                      > > S.Tobias wrote:[color=darkred]
                      > > >
                      > > > pete <pfiland@mindsp ring.com> wrote:
                      > > > > S.Tobias wrote:
                      > > > > >
                      > > > > > pete <pfiland@mindsp ring.com> wrote:
                      > > > > > > S.Tobias wrote:
                      > > > > > > >
                      > > > > > > > int *ip;
                      > > > > > > > char *cp;
                      > > > > > > > void *vp;
                      > > > > > > >
                      > > > > > > > cp = malloc(2 * sizeof(int));
                      > > > > > > > cp++; //defined
                      > > > > > > > vp = cp; //defined
                      > > > > > > > ip = vp; //???
                      > > > > >
                      > > > > > > Assuming that sizeof(int) is greater than one,
                      > > > > > > ip = vp;
                      > > > > > > is not defined.
                      > > > > >
                      > > > > > Why?
                      > > >
                      > > > > Because vp holds an address which is not aligned for type int.
                      > > >
                      > > > Which point in the Std did you apply to explain this?[/color]
                      > >
                      > > It would be from C89
                      > > C89 Last public draft
                      > >
                      > > 3.3.4 Cast operators
                      > >
                      > > A pointer to an object or incomplete type may be converted to a
                      > > pointer to a different object type or a different incomplete type.
                      > > The resulting pointer might not be valid if it is improperly
                      > > aligned for the type pointed to.[/color][/color]
                      [color=blue]
                      > N869
                      > 6.3.2.3 Pointers
                      > [#7] A pointer to an object or incomplete type may be
                      > converted to a pointer to a different object or incomplete
                      > type. If the resulting pointer is not correctly aligned
                      > for the pointed-to type, the behavior is undefined.[/color]

                      Now, why do you think (again, I mean C&V) that a reverse conversion
                      must _always_ work:
                      int *ip;
                      void *vp;
                      ip = ...; //assume valid pointer
                      vp = ip;

                      --
                      Stan Tobias
                      sed 's/[A-Z]//g' to email

                      Comment

                      • pete

                        #56
                        Re: struct and union alignment

                        S.Tobias wrote:[color=blue]
                        >
                        > pete <pfiland@mindsp ring.com> wrote:[color=green]
                        > > pete wrote:[color=darkred]
                        > > >
                        > > > S.Tobias wrote:
                        > > > >
                        > > > > pete <pfiland@mindsp ring.com> wrote:
                        > > > > > S.Tobias wrote:
                        > > > > > >
                        > > > > > > pete <pfiland@mindsp ring.com> wrote:
                        > > > > > > > S.Tobias wrote:
                        > > > > > > > >
                        > > > > > > > > int *ip;
                        > > > > > > > > char *cp;
                        > > > > > > > > void *vp;
                        > > > > > > > >
                        > > > > > > > > cp = malloc(2 * sizeof(int));
                        > > > > > > > > cp++; //defined
                        > > > > > > > > vp = cp; //defined
                        > > > > > > > > ip = vp; //???
                        > > > > > >
                        > > > > > > > Assuming that sizeof(int) is greater than one,
                        > > > > > > > ip = vp;
                        > > > > > > > is not defined.
                        > > > > > >
                        > > > > > > Why?
                        > > > >
                        > > > > > Because vp holds an address which is not aligned for type int.
                        > > > >
                        > > > > Which point in the Std did you apply to explain this?
                        > > >
                        > > > It would be from C89
                        > > > C89 Last public draft
                        > > >
                        > > > 3.3.4 Cast operators
                        > > >
                        > > > A pointer to an object or incomplete type may be converted to a
                        > > > pointer to a different object type or a different incomplete type.
                        > > > The resulting pointer might not be valid if it is improperly
                        > > > aligned for the type pointed to.[/color][/color]
                        >[color=green]
                        > > N869
                        > > 6.3.2.3 Pointers
                        > > [#7] A pointer to an object or incomplete type may be
                        > > converted to a pointer to a different object or incomplete
                        > > type. If the resulting pointer is not correctly aligned
                        > > for the pointed-to type, the behavior is undefined.[/color]
                        >
                        > Now, why do you think (again, I mean C&V) that a reverse conversion
                        > must _always_ work:
                        > int *ip;
                        > void *vp;
                        > ip = ...; //assume valid pointer
                        > vp = ip;[/color]

                        Because, according to the requoted standard text,
                        ip == vp
                        is guaranteed to be true after that.

                        (C&V, again)

                        N869
                        6.3.2.3 Pointers
                        [#1] A pointer to void may be converted to or from a pointer
                        to any incomplete or object type. A pointer to any
                        incomplete or object type may be converted to a pointer to
                        void and back again; the result shall compare equal to the
                        original pointer.

                        --
                        pete

                        Comment

                        • S.Tobias

                          #57
                          Re: struct and union alignment

                          pete <pfiland@mindsp ring.com> wrote:[color=blue]
                          > S.Tobias wrote:[color=green]
                          > >
                          > > pete <pfiland@mindsp ring.com> wrote:[color=darkred]
                          > > > pete wrote:
                          > > > >
                          > > > > S.Tobias wrote:
                          > > > > >
                          > > > > > pete <pfiland@mindsp ring.com> wrote:
                          > > > > > > S.Tobias wrote:
                          > > > > > > >
                          > > > > > > > pete <pfiland@mindsp ring.com> wrote:
                          > > > > > > > > S.Tobias wrote:
                          > > > > > > > > >
                          > > > > > > > > > int *ip;
                          > > > > > > > > > char *cp;
                          > > > > > > > > > void *vp;
                          > > > > > > > > >
                          > > > > > > > > > cp = malloc(2 * sizeof(int));
                          > > > > > > > > > cp++; //defined
                          > > > > > > > > > vp = cp; //defined
                          > > > > > > > > > ip = vp; //???
                          > > > > > > >
                          > > > > > > > > Assuming that sizeof(int) is greater than one,
                          > > > > > > > > ip = vp;
                          > > > > > > > > is not defined.
                          > > > > > > >
                          > > > > > > > Why?
                          > > > > >
                          > > > > > > Because vp holds an address which is not aligned for type int.
                          > > > > >
                          > > > > > Which point in the Std did you apply to explain this?
                          > > > >
                          > > > > It would be from C89
                          > > > > C89 Last public draft
                          > > > >
                          > > > > 3.3.4 Cast operators
                          > > > >
                          > > > > A pointer to an object or incomplete type may be converted to a
                          > > > > pointer to a different object type or a different incomplete type.
                          > > > > The resulting pointer might not be valid if it is improperly
                          > > > > aligned for the type pointed to.[/color]
                          > >[color=darkred]
                          > > > N869
                          > > > 6.3.2.3 Pointers
                          > > > [#7] A pointer to an object or incomplete type may be
                          > > > converted to a pointer to a different object or incomplete
                          > > > type. If the resulting pointer is not correctly aligned
                          > > > for the pointed-to type, the behavior is undefined.[/color]
                          > >
                          > > Now, why do you think (again, I mean C&V) that a reverse conversion
                          > > must _always_ work:
                          > > int *ip;
                          > > void *vp;
                          > > ip = ...; //assume valid pointer
                          > > vp = ip;[/color][/color]
                          [color=blue]
                          > Because, according to the requoted standard text,
                          > ip == vp
                          > is guaranteed to be true after that.[/color]
                          [color=blue]
                          > (C&V, again)[/color]
                          [color=blue]
                          > N869
                          > 6.3.2.3 Pointers
                          > [#1] A pointer to void may be converted to or from a pointer
                          > to any incomplete or object type. A pointer to any
                          > incomplete or object type may be converted to a pointer to
                          > void and back again; the result shall compare equal to the
                          > original pointer.[/color]

                          1. Why do you think that #7 does not apply this time?

                          2. Why #1 does not apply to void* -> int* conversion?

                          What are the rules by which you choose which point applies to what
                          conversion type?

                          --
                          Stan Tobias
                          sed 's/[A-Z]//g' to email

                          Comment

                          • Dan Pop

                            #58
                            Re: [OT] struct and union alignment

                            In <2rk0c8F1bpl5cU 2@uni-berlin.de> "S.Tobias" <sNOiSPAMt@amu. edu.pl> writes:
                            [color=blue]
                            >Dan Pop <Dan.Pop@cern.c h> wrote:
                            >[color=green]
                            >> struct { ... } foo, bar, baz;[/color]
                            >[color=green]
                            >> foo, bar and baz are all the objects of this type needed by the program
                            >> and they are used in a single translation unit. What would a tag buy you?[/color]
                            >
                            >I think we're talking of two different things. I used the definition
                            >of an anonymous structure I found in:
                            >http://docs.sun.com/source/816-2460/...xtensions.html[/color]

                            Which, being a C++ compiler extension is certainly topical here, right?

                            Dan
                            --
                            Dan Pop
                            DESY Zeuthen, RZ group
                            Email: Dan.Pop@ifh.de
                            Currently looking for a job in the European Union

                            Comment

                            • Dan Pop

                              #59
                              Re: struct and union alignment

                              In <2rqlf0F1d1o69U 1@uni-berlin.de> "S.Tobias" <sNOiSPAMt@amu. edu.pl> writes:
                              [color=blue]
                              >pete <pfiland@mindsp ring.com> wrote:[color=green]
                              >> S.Tobias wrote:[color=darkred]
                              >> >
                              >> > pete <pfiland@mindsp ring.com> wrote:
                              >> > > pete wrote:
                              >> > > >
                              >> > > > S.Tobias wrote:
                              >> > > > >
                              >> > > > > pete <pfiland@mindsp ring.com> wrote:
                              >> > > > > > S.Tobias wrote:
                              >> > > > > > >
                              >> > > > > > > pete <pfiland@mindsp ring.com> wrote:
                              >> > > > > > > > S.Tobias wrote:
                              >> > > > > > > > >
                              >> > > > > > > > > int *ip;
                              >> > > > > > > > > char *cp;
                              >> > > > > > > > > void *vp;
                              >> > > > > > > > >
                              >> > > > > > > > > cp = malloc(2 * sizeof(int));
                              >> > > > > > > > > cp++; //defined
                              >> > > > > > > > > vp = cp; //defined
                              >> > > > > > > > > ip = vp; //???
                              >> > > > > > >
                              >> > > > > > > > Assuming that sizeof(int) is greater than one,
                              >> > > > > > > > ip = vp;
                              >> > > > > > > > is not defined.
                              >> > > > > > >
                              >> > > > > > > Why?
                              >> > > > >
                              >> > > > > > Because vp holds an address which is not aligned for type int.
                              >> > > > >
                              >> > > > > Which point in the Std did you apply to explain this?
                              >> > > >
                              >> > > > It would be from C89
                              >> > > > C89 Last public draft
                              >> > > >
                              >> > > > 3.3.4 Cast operators
                              >> > > >
                              >> > > > A pointer to an object or incomplete type may be converted to a
                              >> > > > pointer to a different object type or a different incomplete type.
                              >> > > > The resulting pointer might not be valid if it is improperly
                              >> > > > aligned for the type pointed to.
                              >> >
                              >> > > N869
                              >> > > 6.3.2.3 Pointers
                              >> > > [#7] A pointer to an object or incomplete type may be
                              >> > > converted to a pointer to a different object or incomplete
                              >> > > type. If the resulting pointer is not correctly aligned
                              >> > > for the pointed-to type, the behavior is undefined.
                              >> >
                              >> > Now, why do you think (again, I mean C&V) that a reverse conversion
                              >> > must _always_ work:
                              >> > int *ip;
                              >> > void *vp;
                              >> > ip = ...; //assume valid pointer
                              >> > vp = ip;[/color][/color]
                              >[color=green]
                              >> Because, according to the requoted standard text,
                              >> ip == vp
                              >> is guaranteed to be true after that.[/color]
                              >[color=green]
                              >> (C&V, again)[/color]
                              >[color=green]
                              >> N869
                              >> 6.3.2.3 Pointers
                              >> [#1] A pointer to void may be converted to or from a pointer
                              >> to any incomplete or object type. A pointer to any
                              >> incomplete or object type may be converted to a pointer to
                              >> void and back again; the result shall compare equal to the
                              >> original pointer.[/color]
                              >
                              >1. Why do you think that #7 does not apply this time?[/color]

                              Because the standard says so: character and void pointer values have
                              no alignment restrictions. Therefore, when converting something to
                              pointer to void, the resulting value is, by definition, correctly aligned.
                              [color=blue]
                              >2. Why #1 does not apply to void* -> int* conversion?[/color]

                              It does. But #7 applies too. There is no contradiction between the two.
                              #1 says that you can do the conversion and #7 says what happens if the
                              original pointer value was not properly aligned for the type of the result
                              of the conversion.
                              [color=blue]
                              >What are the rules by which you choose which point applies to what
                              >conversion type?[/color]

                              The rest of the standard. Unfortunately, the standard is very poorly
                              written as a reference document: you can't only read the paragraph(s)
                              of immediate interest and expect to get a complete picture of the issue.

                              Dan
                              --
                              Dan Pop
                              DESY Zeuthen, RZ group
                              Email: Dan.Pop@ifh.de
                              Currently looking for a job in the European Union

                              Comment

                              • S.Tobias

                                #60
                                Re: [OT] struct and union alignment

                                Dan Pop <Dan.Pop@cern.c h> wrote:[color=blue]
                                > In <2rk0c8F1bpl5cU 2@uni-berlin.de> "S.Tobias" <sNOiSPAMt@amu. edu.pl> writes:[/color]
                                [color=blue][color=green]
                                > >Dan Pop <Dan.Pop@cern.c h> wrote:
                                > >[color=darkred]
                                > >> struct { ... } foo, bar, baz;[/color]
                                > >[color=darkred]
                                > >> foo, bar and baz are all the objects of this type needed by the program
                                > >> and they are used in a single translation unit. What would a tag buy you?[/color]
                                > >
                                > >I think we're talking of two different things. I used the definition
                                > >of an anonymous structure I found in:
                                > >http://docs.sun.com/source/816-2460/...xtensions.html[/color][/color]
                                [color=blue]
                                > Which, being a C++ compiler extension is certainly topical here, right?[/color]

                                I took the first plausible definition I found. C++ is not topical here,
                                but C++ shares many ideas with C. I thought the definition in above
                                document was not C++ specific. Anonymous structures aren't topical
                                here either. I was casually interested, since someone mentioned them.
                                I think the above example you provided is called "unnamed structure".

                                --
                                Stan Tobias
                                sed 's/[A-Z]//g' to email

                                Comment

                                Working...