Question about void pointers

R

raphfrk

Is this valid?

int a[20];
void *b;

b = (void *)a; // b points to a[0]

b += 5*sizeof(*a); // b points to a[5]

a[5] = 100;

printf( "%d\n" , *((int *)b) ); // prints 100

If so, if a had been a struct, would it still work?

Is there a possibility that the array could contain some padding, so
rather than sizeof, the assignment would be

b += 5*( (void *)(&(a[1])) - (void *)(&(a[0]));

which seems more more complex.

Would any padding be incorporated into sizeof anyway?
 
V

vippstar

Is this valid?

int a[20];
void *b;

b = (void *)a; // b points to a[0]

No need for the cast.
b += 5*sizeof(*a); // b points to a[5]

No, it's not valid. you can not perform arithmetic operations on void
* pointers.
If it compiles, it's because you have extensions enabled. Extensions
are topical to the newsgroup dedicated to the compiler that makes use
of them.
Assuming you had something like

b = ((unsigned char *)b) + 5 * sizeof *a;

Yes, that would be ok.
a[5] = 100;

printf( "%d\n" , *((int *)b) ); // prints 100

Yes, that is valid. Assuming you use my fixes.
If so, if a had been a struct, would it still work?

Yes said:
Is there a possibility that the array could contain some padding, so
rather than sizeof, the assignment would be

No. Arrays don't have padding bytes.
b += 5*( (void *)(&(a[1])) - (void *)(&(a[0]));

which seems more more complex.

Would any padding be incorporated into sizeof anyway?

Yes, sizeof reports the size of an object. Padding bits & bytes belong
to the size of the object.

if sizeof (unsigned int) == 4 and CHAR_BIT == 8, it doesn't mean
unsigned int has 32 value bits.
It might have 16 or less padding bits. (but not more, because of the
guarantee that UINT_MAX >= 65535)
 
S

sh.vipin

Is this valid?

int a[20];
void *b;

b = (void *)a;  // b points to a[0]

b += 5*sizeof(*a); // b points to a[5]

a[5] = 100;

printf( "%d\n" , *((int *)b) ); // prints 100

If so, if a had been a struct, would it still work?

Is there a possibility that the array could contain some padding, so
rather than sizeof, the assignment would be

b += 5*( (void *)(&(a[1])) - (void *)(&(a[0]));

which seems more more complex.

Would any padding be incorporated into sizeof anyway?


b += 5*sizeof(*a); // b points to a[5]
is *incorrect*

when you do
--> char *c; c++; ==> c is incremented by 1
--> long int *x; x++ ==> x is incremented by 4.
--> void *p; p++ //incorrect ==> because compiler doesn't know by what
amount should it increase.

the number by which a pointer value is incremented or decremented is
dependent on type of object pointer is pointing to. This number has a
specific name which i don't remember, but this thing is not defined
for void *

b += 5*( (void *)(&(a[1])) - (void *)(&(a[0]));
here also "+=" operation will be invalid due to pointer
moreover there is no padding in between the arrays.
 
V

vippstar

when you do
--> char *c; c++; ==> c is incremented by 1
--> long int *x; x++ ==> x is incremented by 4.

Wrong, assuming x was initialized, it would be incremented by 1.

Here's proof:

long int i[1], *p = i, *q = &i[1];
printf("%d\n", (int)(q - p));

Will always print 1.
 
B

Ben Pfaff

int a[20];
void *b;

b = (void *)a; // b points to a[0]

b += 5*sizeof(*a); // b points to a[5]

This is incorrect, but it will work if you are using GCC in its
default mode, because GCC assumes that "void" has size 1 for the
purpose of pointer arithmetic. If you want to write code that
conforms to the ANSI C standard, you should give GCC appropriate
options to turn off this feature (-Wpointer-arith or -pedantic).
 
K

Keith Thompson

Is this valid?

int a[20];
void *b;
[...]

b += 5*sizeof(*a); // b points to a[5]
is *incorrect*
Yes.

when you do
--> char *c; c++; ==> c is incremented by 1
--> long int *x; x++ ==> x is incremented by 4.
--> void *p; p++ //incorrect ==> because compiler doesn't know by what
amount should it increase.

the number by which a pointer value is incremented or decremented is
dependent on type of object pointer is pointing to. This number has a
specific name which i don't remember, but this thing is not defined
for void *

You're probably thinking of "stride", though the standard doesn't use
that term.

However, some compilers (particularly gcc) allow arithmetic on void*
as an extension, treating the stride as 1 byte. In my opinion this
extension is a bad idea; it can be convenient, but it doesn't give you
anything you can't do by other means, it has some bizarre
consequences, and as we've seen here it can make it easy to write
non-portable code without realizing it.

If you invoke gcc with the right options (something like "-ansi
-pedantic -Wall -Wextra") it will at least warn you about any attempts
to use this extension.
 
R

raphfrk

b = ((unsigned char *)b) + 5 * sizeof *a;

I see, got to switch to char * so that it can be incremented properly.
Yes, but by using the offsetof() macro in <stddef.h>

I meant to point to the structure.

struct st { int val; } a[100];

void *b;

a[5].val = 100;

b = a;
b = ((unsigned char *)b) + 5 * sizeof *a;

printf( "%d\n" , b->val );
 
R

raphfrk

b = ((unsigned char *)b) + 5 * sizeof *a;

I see, got to switch to char * so that it can be incremented properly.
Yes, but by using the offsetof() macro in <stddef.h>

I meant to point to the structure.

struct st { int val; } a[100];

void *b;

a[5].val = 100;

b = a;
b = ((unsigned char *)b) + 5 * sizeof *a;

printf( "%d\n" , b->val );


or at least

printf( "%d\n" , ((struct st *)b)->val );
 
S

s0suk3

I see, got to switch to char * so that it can be incremented properly.

No, to unsigned char *. But if your compiler can do it with the void
*, then do it with the void *. It's probably specialized for that kind
of stuff anyway.

Sebastian
 
V

vippstar

No, to unsigned char *. But if your compiler can do it with the void
*, then do it with the void *. It's probably specialized for that kind
of stuff anyway.

You can have the "worst advice of the month" clc award.
You have two options, do it portably, or do it with an extension, with
absolutely no loss in efficiency or size, and you advice to choose the
extension.
 
S

s0suk3

You can have the "worst advice of the month" clc award.
You have two options, do it portably, or do it with an extension, with
absolutely no loss in efficiency or size, and you advice to choose the
extension.

Well, perhaps the OP doesn't need portability (or at least not this
kind of portability). Besides, void * seems more natural for this kind
of task.

Sebastian
 
K

Keith Thompson

Richard said:
Even if it wasnt initialised it would be incremented by something.

If x isn't initialized, referring to its value invokes undefined
behavior. It's likely, but by no means certain, that the behavior
would be *as if* it were incremented. It's also possible, on some
systems, that x could have a value such that attempting to read it
causes a program crash. (Before you ask, no, I don't have an
example.)
Proof of nothing. You are, again, being purposely difficult.

The ++ operator increments its operand by 1, by definition. The
question is, 1 what? In the case of:

long int *x = some_value;
x ++;

it advances it by 1 long int object, i.e., causes it to point to the
next adjacent long int object in memory, assuming that such an object
exists; it can also legally point just past the end of an array.
long int i[1], *p = i, *q = &i[1];

Note that evaluating &i[1] is ok, and equivalent to i+1, but only
because of a special-case rule; see C99 6.5.3.2p3.

Yes, because of the way pointer subtraction is defined.
And the following:

int main() {
long int i[1], *p = i, *q = &i[1];
printf("%u\n",p++);
printf("%u\n",p++);
printf("%u\n", (int)(p - q));

}

The first printf gives me:

3214862936

And the second:

3214862940

Now, that is 4. On my machine.

You're using "%u" to print pointer values. Surely you know that
invokes undefined behavior, and I know of common real-world systems
where it won't work (e.g., where int is 32 bits and pointers are 64
bits). You're also using "%u" to print an int value; if you had
written
printf("%u\n", (unsigned)(p - q));
that wouldn't be no problem. (Actually printing a non-negative int
value using %u is probably ok, due to another special-case rule, but
there's no point in taking advantage of that fact.) Finally, p starts
as a pointer to the first and only element of a 1-element array. You
increment it twice, causing it to point *past* the end of the array.
Yet another instance of undefined behavior that happens to "work" on
your system -- and it wasn't even necessary to demonstrate your point.

You're making unwarranted (though commonly valid) assumptions about
pointer representations and conversions. This program:

#include <stdio.h>
int main(void)
{
long array[10];
long *p = &array[0];
long *q = &array[1];
printf("%d %d %d\n",
(int)sizeof(long), (int)(q - p), (int)q - (int)p);
return 0;
}

will typically print "4 1 4" on a system where sizeof(long)==4. I've
worked on a real-world system where it would print "8 1 1" due to a
rather unusual pointer representation.

And the thing is, all this undefined behavior wasn't even necessary to
demonstrate your point. Here's a portable program (with
implementation-defined but not undefined behavior) that illustrates
what you're trying to talk about:

#include <stdio.h>
#include <assert.h>
int main(void)
{
long array[10];
long *p = &array[0];
long *q = &array[1];
int diff = q - p;
int byte_diff = (char*)q - (char*)p;
printf("p = %p\n", (void*)p);
printf("q = %p\n", (void*)q);
printf("sizeof(long) = %d\n", (int)sizeof(long));
printf("diff = %d\n", diff);
printf("byte_diff = %d\n", byte_diff);
assert(diff == 1);
assert(byte_diff == sizeof(long));
return 0;
}

On my system, I get:

p = 0xbfce19ac
q = 0xbfce19b0
sizeof(long) = 4
diff = 1
byte_diff = 4

And here's the point:

p++ increments p by 1. If p is a long*, this means that it advances
the memory location to which it points by 1 long, or by sizeof(long)
bytes.
 
B

Ben Pfaff

You have two options, do it portably, or do it with an extension, with
absolutely no loss in efficiency or size, and you advice to choose the
extension.

I admit that, occasionally, I've used pointer arithmetic on void
* in cases where GCC is the only compiler that matters. (Code
inside the Linux kernel is one example.) The nice thing about
doing it that way is that it avoids having to insert additional
casts, which are ugly.

I wouldn't do it in a place where portability matters.
 
J

jameskuyper

Richard said:
Even if it wasnt initialised it would be incremented by something.

On real, widely used machines, attempting to access an unitialized
pointer value can cause your program to abort before that value ever
gets a chance to be incremented.

....
long int i[1], *p = i, *q = &i[1];
printf("%d\n", (int)(q - p));

Will always print 1.

And the following:

int main() {
long int i[1], *p = i, *q = &i[1];
printf("%u\n",p++);
printf("%u\n",p++);

That is undefined behavior by reason of trying to print an pointer
value using a format string that calls for an unsigned integer. The
behavior is technically meaningless, though in practice it will
produce much the same effect as casting the the pointer value to
unsigned int on many systems. You could have demonstrated your point
without undefined behavior by using uintptr_t; why didn't you?
printf("%u\n", (int)(p - q));

}

The first printf gives me:

3214862936

And the second:

3214862940

Now, that is 4. On my machine.

Yes, but that difference has no portable meaning, and the
implementation-specific meaning on your machine is (probably) only
that p and q point at locations 4 bytes apart; that doesn't say
anything about how much has been added to q to get the current value
of p.

It is only the third printf() that provides a meaningful answer to the
question of how big the difference is between p and q is. You'll get a
different answer, if you cast both pointer to char* before subtracting
them. On your machine that answer will probably be 4, but that answer
is to a different question,
 
K

Keith Thompson

b = ((unsigned char *)b) + 5 * sizeof *a;

I see, got to switch to char * so that it can be incremented properly.
Yes, but by using the offsetof() macro in <stddef.h>

I meant to point to the structure.

struct st { int val; } a[100];

void *b;

a[5].val = 100;

b = a;
b = ((unsigned char *)b) + 5 * sizeof *a;

printf( "%d\n" , b->val );

If you want to point to a structure, why not just use a
pointer-to-structure rather than a pointer-to-void?

But if you must use void* for some reason, I think this is more
straightforward:

b = (struct st*)b + 5;
 
S

sh.vipin

 In my opinion this
extension is a bad idea; it can be convenient, but it doesn't give you
anything you can't do by other means, it has some bizarre
consequences,


I think Bus Error,on some machines, is one of those consequences.
Thanks all for gcc info. I thought gcc didn't take anything as stride
value for void pointers
 
R

Richard

Keith Thompson said:
If x isn't initialized, referring to its value invokes undefined
behavior. It's likely, but by no means certain, that the behavior
would be *as if* it were incremented. It's also possible, on some
systems, that x could have a value such that attempting to read it
causes a program crash. (Before you ask, no, I don't have an
example.)

Whatever. x will be incremented.
Proof of nothing. You are, again, being purposely difficult.

The ++ operator increments its operand by 1, by definition. The
question is, 1 what? In the case of:

long int *x = some_value;
x ++;

it advances it by 1 long int object, i.e., causes it to point to the
next adjacent long int object in memory, assuming that such an object
exists; it can also legally point just past the end of an array.
long int i[1], *p = i, *q = &i[1];

Note that evaluating &i[1] is ok, and equivalent to i+1, but only
because of a special-case rule; see C99 6.5.3.2p3.

Yes, because of the way pointer subtraction is defined.
And the following:

int main() {
long int i[1], *p = i, *q = &i[1];
printf("%u\n",p++);
printf("%u\n",p++);
printf("%u\n", (int)(p - q));

}

The first printf gives me:

3214862936

And the second:

3214862940

Now, that is 4. On my machine.

You're using "%u" to print pointer values. Surely you know that
invokes undefined behavior, and I know of common real-world systems

Garbage. On my machine it prints a 32 bit value. Pointers are values
which I can printf and see and they correspond to physical memory
locations. Its a number get over it.
 
R

Richard

On real, widely used machines, attempting to access an unitialized
pointer value can cause your program to abort before that value ever
gets a chance to be incremented.

Never come across it. Which machines? I do believe you btw. However in
the great majority (99.9999%= of machines on this planet it will indeed
by incremented.
...
long int i[1], *p = i, *q = &i[1];
printf("%d\n", (int)(q - p));

Will always print 1.

And the following:

int main() {
long int i[1], *p = i, *q = &i[1];
printf("%u\n",p++);
printf("%u\n",p++);

That is undefined behavior by reason of trying to print an pointer
value using a format string that calls for an unsigned integer. The
behavior is technically meaningless, though in practice it will
produce much the same effect as casting the the pointer value to
unsigned int on many systems. You could have demonstrated your point
without undefined behavior by using uintptr_t; why didn't you?
printf("%u\n", (int)(p - q));

}

The first printf gives me:

3214862936

And the second:

3214862940

Now, that is 4. On my machine.

Yes, but that difference has no portable meaning, and the

It has a meaning. The VALUE of p is incremented by 4. On my machine. And
probably the OPs.
implementation-specific meaning on your machine is (probably) only
that p and q point at locations 4 bytes apart; that doesn't say
anything about how much has been added to q to get the current value
of p.

It is only the third printf() that provides a meaningful answer to the
question of how big the difference is between p and q is. You'll get a
different answer, if you cast both pointer to char* before subtracting
them. On your machine that answer will probably be 4, but that answer
is to a different question,

--
 
S

s0suk3

     "This kind of task" was an artificial bit of code specifically
written to experiment with manipulating pointers.  An investigative
doodle, nothing more.

No. This "investigate doodle" demonstrated this kind of task. But this
kind of task is also common in real-world programs, and it's
important. I, for one, have actually done this, without realizing I
was using an extension.
     Personally, I'm not as ready as vippstar is to give you the
award; we're only halfway through the month.  But I'd be surprised
if you weren't on the ballot a couple weeks from now.  Have you
chosen your running mate yet?

I did not understand a word of that paragraph.

Sebastian
 
K

Keith Thompson

I think Bus Error,on some machines, is one of those consequences.

Not really. Or rather, any misuse of arithmetic on void* that might
give you a bus error would almost certainly do the same thing if you
use the standard C equivalent (converting to and from character
pointers).

[...]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top