When is a cast not a cast? 
Author Message
 When is a cast not a cast?

Here's one that popped up last night/this morning (keep that Sanka
away from me! %-S )

I wanted to be a 'good little programmer' and make all the types
match up, so I was using casts wherever a promotion might be
non-obvious.  In particular, I fell for:  (the line numbers are shown
only for reference)

1   main()
2   {
3       char *c;
4       char *p;
5       int i;
6       ...
7       c = "somestring";  /* Nothing fancy, null-terminated. */
8       i = 4;  /* For example. */
9       ...
10      p = (c + (char *) i);  /* More trouble than it's worth... */
11      ...
12  }

wherupon both the lint(1) and cc(1) in my Ultrix 2.2 piped-up with
warnings that the 'operands of + have incompatible types' on line 10...

Now, who is having the more serious problem with (reduntantly?) casting
i to be a char * before this addition: me, or the programmming tools
under Ultrix version 2.2?

How can two things explicitly identifiable as being the same type
(one by declaration, the other by that all-powerful fiat, the cast)
be suddenly 'incompatible'?

I have an inkling as to what I'm missing, but it makes little sense
regardless:  It involves getting the integer quantity (i * sizeof(char *))
which leaves one right back in the pigpen wondering how to cast this greater
integer as in

        p = (c + (char *)( i * sizeof(char *) );

I get the feeling that one isn't allowed pointer arithmetic at all.
It only seems to allow such things as " &(foo[bar]) - foo ", where it
is 100% certain that both operands point to the same data segment.

Additional info:
 - lexical order of c and (char *)i on line 10 above is immaterial;
 - the extra parentheses are immaterial;
 - initialization method is immaterial;
 - declaring c as '(3)  char c[];' changes nothing;
 - declaring i as '(5)  char *i;' then setting '(8)  i = (char *) 4;' convinces
     lint to say:
      'foo.c(10): warning: illegal combination of pointer and integer, op ='
     as well as the same-old-same-old about 'incompatible types';
 - I haven't checked it on other compilers.

                                --Blair
                                  "Goodness!  A conundrum. `,:-q"



Sat, 17 Oct 1992 10:50:00 GMT  
 When is a cast not a cast?

Quote:
> 1   main()
> 2   {
> 3  char *c;
> 4  char *p;
> 5  int i;
> 6  ...
> 7  c = "somestring";  /* Nothing fancy, null-terminated. */
> 8  i = 4;  /* For example. */
> 9  ...
> 10         p = (c + (char *) i);  /* More trouble than it's worth... */
> 11 ...
> 12  }

> wherupon both the lint(1) and cc(1) in my Ultrix 2.2 piped-up with
> warnings that the 'operands of + have incompatible types' on line 10...

Well, first of all, the only arithmetic operations allowed on pointers
are pointer+integer, integer+pointer, pointer-integer, and pointer-pointer.
Pointer+pointer is illegal, and therefore, "operands of + have incompatible
types".

Secondly, I believe what you *want* on line 10 is

                                p = c + i;

This is equivalent to "p = &(c[i]);".  It sets p equal to a pointer to the
i'th char after c.

--
Jeff Erickson       Claris Corporation  | Birdie, birdie, in the sky,
408/987-7309      Applelink: Erickson4  |   Why'd you do that in my eye?

       "I'm a heppy, heppy ket!"        |   I'm just glad that cows don't fly.



Sat, 17 Oct 1992 12:37:00 GMT  
 When is a cast not a cast?

| I wanted to be a 'good little programmer' and make all the types
| match up, so I was using casts wherever a promotion might be
| non-obvious.  In particular, I fell for:  (the line numbers are shown
| only for reference)
|
| 1   main()
| 2   {
| 3     char *c;
| 4     char *p;
| 5     int i;
| 6     ...
| 7     c = "somestring";  /* Nothing fancy, null-terminated. */
| 8     i = 4;  /* For example. */
| 9     ...
| 10    p = (c + (char *) i);  /* More trouble than it's worth... */
| 11    ...
| 12  }
|
| wherupon both the lint(1) and cc(1) in my Ultrix 2.2 piped-up with
| warnings that the 'operands of + have incompatible types' on line 10...

  C allows expressions involving a pointer and an int. The expression
        ptr + int
has the same type as ptr, and the address "ptr plus (int times the size
of the base type of ptr). The following expressions refer to the same
location, using the declarations at the start of the example:
        /* declare */
        int *ptr;       /* this is our pointer */
        int m;          /* this is the int we add */
        int *value;     /* this holds the resulting address */

        /* these result in the same value */
        value = (ptr + m);      /* parens optional */
        value = &ptr[m];
        value = &m[ptr];    /* ugly and confusing, but legal */

  In addition to the result of adding (or subtracting) an int and
pointer, the result of subtracting two pointers is an int, the number of
items of the base type of the pointers, subject to the following:
        a) the pointers must be of the same type
        b) the pointers must be into the same data structure
           or the results will not be portable (and may not
           work at all in some implementations).

  For example:
        int p[20], *ptr1, *ptr2, value;

        ptr1 = &p[0];
        ptr2 = &p[4];
        value = ptr2 - ptr1;    /* always 4 */

  regardless of the sizeof(int), the resul;t is four, because it is the
*number of items* of the base type between the pointers. Changing the
'int' type to any other type, including struct and union types, will not
effect the value of the subtraction. This eliminates some of the address
arithmetic tricks required by older languages.

  The reason that you are getting errors is that you are trying to add
two pointers, which is not a defined operation. Looking at your original
code again,

| 10    p = (c + (char *) i);  /* More trouble than it's worth... */

what you want is just
        p = c + i;              /* no trouble at all */

Hope I made this clear, it's harder to understand once you learn it
wrong... I'm sure the usual people who respond to every question will
reply to this one.
--

  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me



Sat, 17 Oct 1992 13:08:00 GMT  
 When is a cast not a cast?

Quote:

> [some stuff about pointers which has been conquered with aplomb by
> Bill Davidson et al...but the stuff that gets me is...]

> | 3        char *c;
> ...
> | 7        c = "somestring";  /* Nothing fancy, null-terminated. */

Now I always thought this kind of thing was extremely bad form, but
I've recently seen a couple of code examples that use this.
One figures that if ``somestring'' is generated by the compiler somewhere,
then the assignment will work as expected, because the address of it will
be copied to ``c''. But what if the compiler decides that ``somestring''
has finished it's duty to the program, and overwrites the space it took
with something else? Then ``c'' points to rubbish. Right?

I've always used stuff like ``char *c = "string";'' which the compiler
should know how to deal with, as it's an initializer, or something along
the lines of
        char *c;
        c = (char *) malloc(something);
        strcpy(c, somethingelse);

Have I been misguided all this time?

rob



Sat, 17 Oct 1992 14:06:00 GMT  
 When is a cast not a cast?

| Here's one that popped up last night/this morning (keep that Sanka
| away from me! %-S )
|
| I wanted to be a 'good little programmer' and make all the types
| match up, so I was using casts wherever a promotion might be
| non-obvious.  In particular, I fell for:  (the line numbers are shown
| only for reference)
|
| 1   main()
| 2   {
| 3     char *c;
| 4     char *p;
| 5     int i;
| 6     ...
| 7     c = "somestring";  /* Nothing fancy, null-terminated. */
| 8     i = 4;  /* For example. */
| 9     ...
| 10    p = (c + (char *) i);  /* More trouble than it's worth... */
| 11    ...
| 12  }
|
| wherupon both the lint(1) and cc(1) in my Ultrix 2.2 piped-up with
| warnings that the 'operands of + have incompatible types' on line 10...
|
| Now, who is having the more serious problem with (reduntantly?) casting
| i to be a char * before this addition: me, or the programmming tools
| under Ultrix version 2.2?

        [ stuff deleted ]

        But you want p to point into the string by an offset i.

        Line 10 should simply be

                p       = c + i;

        so that the value of pointer c is incremented by the value of integer i
times the sizeof a char.

        You don't want to add two *pointers* together and place the result in
p.  Think about the result from subtacting two pointers:

        char    c [8];
        char    *p;
        int     i;

        p       = &c [7];
        i       = p - c;

        The result of p - c is 8, an integer.

--rkl



Sat, 17 Oct 1992 16:10:00 GMT  
 When is a cast not a cast?

Quote:
>10  p = (c + (char *) i);  /* More trouble than it's worth... */

Addition of pointers is a meaningless operation.


Sat, 17 Oct 1992 16:30:00 GMT  
 When is a cast not a cast?

Quote:
> 3  char *c;
> 4  char *p;
> 5  int i;
> 6  ...
> 7  c = "somestring";  /* Nothing fancy, null-terminated. */
> 8  i = 4;  /* For example. */
> 10         p = (c + (char *) i);  /* More trouble than it's worth... */
> wherupon both the lint(1) and cc(1) in my Ultrix 2.2 piped-up with
> warnings that the 'operands of + have incompatible types' on line 10...

Correct.  You cannot add two pointers -- you can only add
a pointer and an integer.

You can SUBTRACT two pointers (to the same type); the result
of that is an integer, not a pointer.

If p is a pointer to element n of some array, then p+i is a
pointer to element n+i of that array.

If p isn't a pointer to an array element, you're on your own.
[C-T&P, p. 29]
--
                                --Andrew Koenig



Sat, 17 Oct 1992 16:36:00 GMT  
 When is a cast not a cast?

Quote:

>Right?

Wrong.

Quote:
>Have I been misguided all this time?

Yes.


Sat, 17 Oct 1992 17:34:00 GMT  
 When is a cast not a cast?
[char *c = "somestring";]

Quote:

>Now I always thought this kind of thing was extremely bad form, but
>I've recently seen a couple of code examples that use this.
>One figures that if ``somestring'' is generated by the compiler somewhere,
>then the assignment will work as expected, because the address of it will
>be copied to ``c''.

This is correct.  The array-11-of-char

        {'s', 'o', 'm', 'e', 's', 't', 'r', 'i', 'n', 'g', '\0'}

is generated (somewhere, somehow) by the compiler; the value of the
double-quoted expression is thus an object of type

        char [11]

which in this context is immediately converted to one of type

        char *

whose value is the address of the first `s' (wherever the compiler
has placed it).

Quote:
>But what if the compiler decides that ``somestring'' has finished its
>duty to the program, and overwrites the space it took with something
>else?

Then the compiler has a bug.

Objects created with "foo" have type array-N-of-char and storage class
*static* (and no name, hence no scope class).  They must be created by
the time the runtime system calls main() and live unchanged (unless
overwritten by programmer error) until the program exits.

It is possible for the *programmer* to (attempt to) overwrite the space
with something else:

        strcpy("here is some static string space", "but this is a bad idea");

In particular, this is allowed to fail (with `segmentation fault - core
dumped' or the like) at runtime.  Traditionally, Unix C compilers have
placed these strings in a read/write data area along with other
initialised global and static variables, but newer compilers (gcc) put
them in the text segment instead.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)



Sat, 17 Oct 1992 23:37:00 GMT  
 When is a cast not a cast?

Quote:
>I wanted to make all the types match up, so I was using casts
>wherever a promotion might be non-obvious.  In particular, I fell for:
>3   char *c;
>5   int i;
>7   c = "somestring";  /* Nothing fancy, null-terminated. */
>8   i = 4;  /* For example. */
>10  p = (c + (char *) i);  /* More trouble than it's worth... */
>wherupon cc(1) said that the 'operands of + have incompatible types'

>Now, who is having the more serious problem with (reduntantly?) casting
>i to be a char * before this addition: me, or the programmming tools
>under Ultrix version 2.2?

It isn't even redundant.  It means the wrong thing.  Casts tend not
to be redundant.  Sometimes they are used for "portability".  Not here.

A better example is
        p = "foobar" + "barfoo";    /* what does this mean? */
The line
        p = c + i;      /* means p = c[i] or p = i[c] or p = i + c */
does something useful.

K&R says something about what arithmetic can be done with pointers.
I'd quote from the bible were it required.

Stephen.



Sat, 17 Oct 1992 23:38:00 GMT  
 
 [ 40 post ]  Go to page: [1] [2] [3]

 Relevant Pages 

1. malloc: to cast or not to cast

2. to cast or not to cast?

3. Discarded Function Values (To Cast or Not to Cast)

4. old style casts vs new style casts

5. casting of struct element void pointer casting

6. Cast...always cast...

7. Need help with reinterpret_cast, a C-style cast or function-style cast

8. old style casts vs new style casts

9. Need help with reinterpret_cast, a C-style cast or function-style cast

10. CString cast to LPCTSTR cast error

11. Need help with reinterpret_cast, a C-style cast or function-style cast

12. CString cast to LPCTSTR cast error

 

 
Powered by phpBB® Forum Software