Code Comments
Programming Forum and web based access to our favorite programming groups.I recently upgraded my Arch Linux system to GCC 3.4, and found out that a previously accepted behavior (cast-as-lvalue) is now marked as deprecated, and will cease to function in GCC 3.5. This has caused several builds to break, most notably elfutils. Presumably this behavior is not part of the C standard and it is thus being excised like many other nonstandard GCC extensions. Regardless, my question is not about the specifics or politics of GCC or any compiler. Much of the code I'm trying to fix involves things like the following: *((some_type *) ptr)++; The desired behavior in this case is to increment the pointer as if it were a (some_type *). In some cases, the pointer is typed as void, in other cases it has a specific type, but regardless the compiler needs to treat it as a different type when it is incrementing it. Now I personally think cast-as-lvalue is a very logical way to attack this problem, but apparently enough don't that it's been deprecated. My question, then, is how to get the same exact behavior, but within the C spec? My current instinct is to do something as follows. Assume the current code is: foo *ptr; *((bar *) ptr)++; I would do the following: foo *ptr; bar *temp = (bar *)ptr; *temp++; ptr = (foo *)temp; Is there any better way to do this? This seems like quite a bit of extra code to avoid what (at least to me) looks like the logical way of expressing this behavior. -- Mike
Post Follow-up to this messageOn Mon, 23 Aug 2004, Michael Baehr wrote: > > The desired behavior in this case is to increment the pointer as if it > were a (some_type *). In some cases, the pointer is typed as void, in > other cases it has a specific type, but regardless the compiler needs to > treat it as a different type when it is incrementing it. [not valid C code] > foo *ptr; > *((bar *) ptr)++; [valid C code] > foo *ptr; > bar *temp = (bar *)ptr; > *temp++; > ptr = (foo *)temp; This works, but you might as well compress it into one line and lose the temporary: foo *ptr; ptr = (foo *)((bar *)ptr + 1); Note that if 'foo' is 'void', you can drop the redundant cast, too: void *ptr; ptr = (bar *)ptr + 1; HTH, -Arthur
Post Follow-up to this messageOn Mon, 23 Aug 2004, Michael Baehr wrote: > I recently upgraded my Arch Linux system to GCC 3.4, and found out that a > previously accepted behavior (cast-as-lvalue) is now marked as deprecated, > and will cease to function in GCC 3.5. This has caused several builds to > break, most notably elfutils. > > Presumably this behavior is not part of the C standard and it is thus > being excised like many other nonstandard GCC extensions. Regardless, my > question is not about the specifics or politics of GCC or any compiler. > > Much of the code I'm trying to fix involves things like the following: > > *((some_type *) ptr)++; This isn't cast-as-lvalue but a normal cast. Standard C, though the result is often undefined. AFAIK, the equivalent cast-as-lvalue would be: ((some_type)*ptr)++;
Post Follow-up to this messageOn Tue, 24 Aug 2004, Jarno A Wuolijoki wrote: > On Mon, 23 Aug 2004, Michael Baehr wrote: > > > This isn't cast-as-lvalue but a normal cast. Standard C, though the > result is often undefined. I re-engage my brain and take my word back: *((some_type *) ptr)++; != (*((some_type *) ptr))++; Sigh. Why is it that I always hit send before catching these details..
Post Follow-up to this messageIn article <pan.2004.08.23.22.21.51.353227@spamblocked.com>,
Michael Baehr <usemike@spamblocked.com> wrote:
>*((some_type *) ptr)++;
As you note, this is not standard C (it was present in early C89
drafts, but removed). On machines where pointers to all types look
the same, declaring a union of pointer types is likely to work:
union {some_type *st; other_type *ot;} foo;
*foo.st++;
-- Richard
Post Follow-up to this messageOn Tue, 24 Aug 2004 00:51:57 +0300, Jarno A Wuolijoki wrote: > I re-engage my brain and take my word back: > *((some_type *) ptr)++; != (*((some_type *) ptr))++; > > Sigh. Why is it that I always hit send before catching these details.. I think it's one of those unwritten laws of USENET. Cheers ;) -- Mike
Post Follow-up to this message# Much of the code I'm trying to fix involves things like the following:
#
# *((some_type *) ptr)++;
#
# The desired behavior in this case is to increment the pointer as if it
# were a (some_type *). In some cases, the pointer is typed as void, in
# other cases it has a specific type, but regardless the compiler needs to
# treat it as a different type when it is incrementing it.
You can get a lvalue by judicious use of & and *.
lvalue ref char s
ref ref char (&s)
ref ref int (int**)(&s)
lvalue ref int *((int**)(&s))
(cd /tmp
rm a.out
cat >x.c <<':eof'
#include <stdio.h>
#include <stdlib.h>
#define lvaluecast(type,lvalue) (*((type*)((void*)(&(lvalue)))))
int main(int N,char **P) {
char *s = malloc(27),*s0; int v;
strcpy(s,"abcdefghijklmnopqrstuvwxyz");
s0 = s;
v = *lvaluecast(int*,s)++;
printf("s0=%p s=%p %d v=%x\n",s0,s,s-s0,v);
return 0;
}
:eof
cc x.c
a.out)
s0=0x300140 s=0x300144 4 v=61626364
--
SM Ryan http://www.rawbw.com/~wyrmwif/
Raining down sulphur is like an endurance trial, man. Genocide is the
most exhausting activity one can engage in. Next to soccer.
Post Follow-up to this message
On Tue, 24 Aug 2004, SM Ryan wrote:
[Someone else wrote, I assume:]
> # Much of the code I'm trying to fix involves things like the following:
> #
> # *((some_type *) ptr)++;
> #
> # The desired behavior in this case is to increment the pointer as if it
> # were a (some_type *). In some cases, the pointer is typed as void, in
> # other cases it has a specific type, but regardless the compiler needs to
> # treat it as a different type when it is incrementing it.
SM Ryan: Please don't use # as a "quoting" mechanism, because it's
annoying, it's hard to read and it breaks many line-wrapping programs.
(Also, please endeavor not to tell untruths to newbies, but I'll give
you the benefit of the doubt this time. See below.)
> You can get a lvalue by judicious use of & and *.
>
> lvalue ref char s
> ref ref char (&s)
> ref ref int (int**)(&s)
> lvalue ref int *((int**)(&s))
Undefined behavior. You can tell it's suspect without even knowing
the Standard, because I could drop one line in your "derivation" and come
up with the same answer where it's more obviously incorrect.
lvalue ref char s
ref ref int (int**)s
lvalue ref int *(int**)s
> (cd /tmp
> rm a.out
> cat >x.c <<':eof'
> #include <stdio.h>
> #include <stdlib.h>
>
> #define lvaluecast(type,lvalue) (*((type*)((void*)(&(lvalue)))))
Overly complicated
#define lvaluecast(type,lvalue) (*(type*)&(lvalue))
and insufficiently general
lvaluecast(void(*)(), fnptr) = bar;
and flat-out wrong.
assert(sizeof(char) != sizeof(int));
lvaluecast(int, mychar[0]) = 255;
printf("%d\n", mychar[1]);
> int main(int N,char **P) {
> char *s = malloc(27),*s0; int v;
> strcpy(s,"abcdefghijklmnopqrstuvwxyz");
> s0 = s;
> v = *lvaluecast(int*,s)++;
Here is the crash. If sizeof(char*)!=sizeof(int*), you are
overwriting memory you don't own. If the layouts of the two
types are different, you are causing serious Bad Stuff. No
matter what, this code is dangerous.
> printf("s0=%p s=%p %d v=%x\n",s0,s,s-s0,v);
And just for the record:
printf("s0=%p s=%p %d v=%x\n",(void*)s0,(void*)s,s-s0,(unsigned)v);
although some people think the first two casts aren't needed when 's0'
and 's' are pointers to 'char'. I put them in anyway.
> return 0;
> }
-Arthur
Post Follow-up to this messageIn article <pan.2004.08.23.22.21.51.353227@spamblocked.com>,
Michael Baehr <usemike@spamblocked.com> wrote:
>*((some_type *) ptr)++;
As you note, this is not standard C (it was present in early C89
drafts, but removed). On machines where pointers to all types look
the same, declaring a union of pointer types is likely to work:
union {some_type *st; other_type *ot;} foo;
*foo.st++;
-- Richard
Post Follow-up to this message
On Tue, 24 Aug 2004, SM Ryan wrote:
[Someone else wrote, I assume:]
> # Much of the code I'm trying to fix involves things like the following:
> #
> # *((some_type *) ptr)++;
> #
> # The desired behavior in this case is to increment the pointer as if it
> # were a (some_type *). In some cases, the pointer is typed as void, in
> # other cases it has a specific type, but regardless the compiler needs to
> # treat it as a different type when it is incrementing it.
SM Ryan: Please don't use # as a "quoting" mechanism, because it's
annoying, it's hard to read and it breaks many line-wrapping programs.
(Also, please endeavor not to tell untruths to newbies, but I'll give
you the benefit of the doubt this time. See below.)
> You can get a lvalue by judicious use of & and *.
>
> lvalue ref char s
> ref ref char (&s)
> ref ref int (int**)(&s)
> lvalue ref int *((int**)(&s))
Undefined behavior. You can tell it's suspect without even knowing
the Standard, because I could drop one line in your "derivation" and come
up with the same answer where it's more obviously incorrect.
lvalue ref char s
ref ref int (int**)s
lvalue ref int *(int**)s
> (cd /tmp
> rm a.out
> cat >x.c <<':eof'
> #include <stdio.h>
> #include <stdlib.h>
>
> #define lvaluecast(type,lvalue) (*((type*)((void*)(&(lvalue)))))
Overly complicated
#define lvaluecast(type,lvalue) (*(type*)&(lvalue))
and insufficiently general
lvaluecast(void(*)(), fnptr) = bar;
and flat-out wrong.
assert(sizeof(char) != sizeof(int));
lvaluecast(int, mychar[0]) = 255;
printf("%d\n", mychar[1]);
> int main(int N,char **P) {
> char *s = malloc(27),*s0; int v;
> strcpy(s,"abcdefghijklmnopqrstuvwxyz");
> s0 = s;
> v = *lvaluecast(int*,s)++;
Here is the crash. If sizeof(char*)!=sizeof(int*), you are
overwriting memory you don't own. If the layouts of the two
types are different, you are causing serious Bad Stuff. No
matter what, this code is dangerous.
> printf("s0=%p s=%p %d v=%x\n",s0,s,s-s0,v);
And just for the record:
printf("s0=%p s=%p %d v=%x\n",(void*)s0,(void*)s,s-s0,(unsigned)v);
although some people think the first two casts aren't needed when 's0'
and 's' are pointers to 'char'. I put them in anyway.
> return 0;
> }
-Arthur
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.