473,722 Members | 2,430 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

void pointer arithmetic

From searching Google Groups, I understand that void pointer arithmetic is a
constraint violation, which is understandable. However, generic functions
like qsort() and bsearch() must in essence do exactly this, and similarly
generic functions seem to have useful applications.

In a few posts I read, it was suggested to avoid void pointer arithmetic by
casting to a char pointer, and performing arithmetic on that (in multiples
of sizeof(original _type)). Thus the pointer is cast through the sequence
original_type* -> void* -> char* -> void* -> original_type*.

I am quite sure this would work on many implementations (where the casts are
no-ops), but the threads I saw containing the above suggestion did not make
clear whether or not it was undefined (or implementation defined)
behaviour - is it? If so, is there any way to achieve the desired effect
while strictly conforming to the standards?

TIA,
Alex
Nov 13 '05 #1
22 12734
Alex Fraser wrote:
From searching Google Groups, I understand that void pointer
arithmetic is a constraint violation, which is understandable.
Yup.
However, generic functions like qsort() and bsearch() must in essence
do exactly this,
No, what these functions do to compare the objects depends on the
original data type of the objects and their semantics. See below.
In a few posts I read, it was suggested to avoid void pointer
arithmetic by casting to a char pointer, and performing arithmetic on
that (in multiples of sizeof(original _type)).
You could, but it's usually cleaner to just cast to pointers the
original type and let the compiler do the sizeof for you.

As for doing pointer arithmetic on the results: If all the pointers
point into the same array, and you really want to sort the pointers by
their index into that array, yes, then you can do that. However,
usually you'll want to do something quite else, e.g.:

static int str_qcmp(const void *a, const void *b)
{
char *const *ap = a;
char *const *bp = b;
return strcmp(*ap, *bp);
}
....
char *arr[] = { "foo", "bar", "baz" };
qsort(arr, sizeof(arr)/sizeof(*arr), sizeof(*arr), str_qcmp);
/* arr = { "bar", "baz", "foo" } */
I am quite sure this would work on many implementations (where the
casts are no-ops),
Never mind that. If casts are not no-ops, the casts will modify the
representations of the pointer as appropriate. Unless you make
the mistake of telling the compiler that some data has another type
than it really has, for example by casting the _function pointer_
to another type. For example, I've seen programs that did this:

static int foo_qcmp(struct foo *a, struct foo *b);
...
qsort(..., (int (*)(const void*, const void*)) foo_qcmp);

Now qsort will pass void pointers to foo_qcmp, but foo_qcmp thinks it is
receives struct foo pointers, so it doesn't convert them from void* to
struct foo*. That fails if void* and struct foo* have different
representations or are passed in different ways to functions.
Thus the pointer is cast through the sequence
original_type* -> void* -> char* -> void* -> original_type*.


The standard allows this, because char* and void* have the same
representation and alignment requirements. However,
original_type* -> void* -> original_type* is quite enough.

--
Hallvard
Nov 13 '05 #2
"Hallvard B Furuseth" <h.b.furuseth(n ospam)@usit.uio (nospam).no> wrote in
message news:HB******** ******@bombur.u io.no...
Alex Fraser wrote:

[snip]
However, generic functions like qsort() and bsearch() must in essence
do exactly this,


No, what these functions do to compare the objects [...]


Sorry, but you totally missed the point, which was the implementation. The
cast sequence I described seems unavoidable. For an equivalent to qsort()
(for example), the first cast happens before you call it, the middle two
within it (with the pointer arithmetic inbetween), and the last in the
comparison function.
Thus the pointer is cast through the sequence
original_type* -> void* -> char* -> void* -> original_type*.


The standard allows this, because char* and void* have the same
representation and alignment requirements.


That's what I needed to know :). Thankyou.

Alex
Nov 13 '05 #3
Alex Fraser wrote:
"Hallvard B Furuseth" <h.b.furuseth(n ospam)@usit.uio (nospam).no> wrote in
message news:HB******** ******@bombur.u io.no...
Alex Fraser wrote:

[snip]
> However, generic functions like qsort() and bsearch() must in essence
> do exactly this,


No, what these functions do to compare the objects [...]


Sorry, but you totally missed the point, which was the implementation. The
cast sequence I described seems unavoidable.


Well, you don't need a cast. You can assign a void * to a char * without
casting. But yes, the conversion is unavoidable, and legal.

--
Richard Heathfield : bi****@eton.pow ernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 13 '05 #4
"Richard Heathfield" <do******@addre ss.co.uk.invali d> wrote in message
news:bp******** **@titan.btinte rnet.com...
Alex Fraser wrote:
The cast sequence I described seems unavoidable.
Well, you don't need a cast. You can assign a void * to a char * without
casting.


Indeed, and the reverse. In fact, all the conversions are to/from void *, so
there's no casting at all.
But yes, the conversion is unavoidable, and legal.


Thanks for the confirmation (that I'm not missing something too).

Alex
Nov 13 '05 #5
On Sun, 16 Nov 2003 22:53:55 -0000, "Alex Fraser" <me@privacy.net >
wrote in comp.lang.c:
"Richard Heathfield" <do******@addre ss.co.uk.invali d> wrote in message
news:bp******** **@titan.btinte rnet.com...
Alex Fraser wrote:
The cast sequence I described seems unavoidable.


Well, you don't need a cast. You can assign a void * to a char * without
casting.


Indeed, and the reverse. In fact, all the conversions are to/from void *, so
there's no casting at all.


No, this is not true. In some cases there is a difference between
casting between a pointer to void and a pointer to some non-character
object type, although not on today's common desktop systems.

There are some systems where the minimum word size addressable by the
processor is large. I have used digital signal processors from
vendors like Texas Instruments and Analog Devices where there is no
direct hardware support for 8-bit types, that is nothing smaller than
16-bit (TI) or 32-bit (AD).

DSPs in general are used almost entirely in what are called
free-standing environments, and their compilers do not bother to
provide an 8-bit type.

But there are other processors without small integer support that do
feel the need to provide more familiar sized characters.

On some such implementations , a pointer to any object type except void
and the character types is the same size as a machine address, but a
pointer to a character type must be larger. It must contain the
address of a machine word and some additional bits to specify what
sub-word field of the word contains the character of interest.

That is why the standard specifically guarantees that a pointer to
void must have the same representation as pointers to the character
types, and does not place the same requirement on pointers to other
data types.

So all pointers are the same size and representation on your
particular platform, and in fact on most platforms, but not on all
platforms.
But yes, the conversion is unavoidable, and legal.


Thanks for the confirmation (that I'm not missing something too).

Alex


--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
Nov 13 '05 #6
>>"Richard Heathfield" <do******@addre ss.co.uk.invali d> wrote in message
news:bp****** ****@titan.btin ternet.com...
... you don't need a cast. You can assign a void * to a char * without
casting.
On Sun, 16 Nov 2003 22:53:55 -0000, "Alex Fraser" <me@privacy.net >
wrote in comp.lang.c:
Indeed, and the reverse. In fact, all the conversions are to/from void *, so
there's no casting at all.

In article news:di******** *************** *********@4ax.c om
Jack Klein <ja*******@spam cop.net> writes:No, this is not true. In some cases there is a difference between
casting between a pointer to void and a pointer to some non-character
object type, although not on today's common desktop systems. ...


[more about byte vs non-byte pointers, snipped]

I do not believe this is what Alex Fraser meant. The quotes I
retained above have to do with the means of achieving the various
pointer conversions. The Standard's constraints on "char *"
imply that any valid data pointer value can be stored in an
object of type "char *", with conversions to and fro giving back
the original pointer (or one that compares equal and is equally
useful, in any case). That is:

char *cp;
double *dp;
... assign some valid value to "dp" ...
cp = (char *)dp;
... any code here that leaves both cp and dp alone ...
*(double *)cp /* has the same effect as *dp */
... code here that modifies "dp"
dp = (double *)cp; /* restores "dp" to the saved value */

Here, the conversions from "double *" to "char *" and back *must*
be done via casts. (As Jack Klein notes, this conversion may indeed
change the underlying bits, so that, e.g., a memory dump of the
memory or registers holding cp and dp would show different values.
If there *is* a change in representation, the one from "double *"
to "char *" is reversible, and "char *" to "double *" reverses it,
except possibly for "padding" bits.)

On the other hand, if we replace "cp" with:

void *vp;

then we can write:

vp = dp;

and later:

dp = vp;

all without casts. (But note that the conversion requested via
*(double *)cp requires either an auxiliary variable such as
"double *dp2", or another cast.) Any actual machine code needed
to convert the "double *" pointer to "void *", and then reverse
that conversion, will still be there, and there is no reason for
code to differ from that for "char *cp".

What Alex Fraser and Richard Heathfield are noting -- correctly --
is that all the intermediate conversions can be written without
the syntactic construct called a "cast". What Jack Klein is noting
-- correctly -- is that they are still conversions. The casts are
"just" syntax by which one can request a conversion; the conversions
are always conversions; and using "void *" allows you to achieve
the desired conversions without the syntax of casts.

The last -- conversions without casts -- can be considered desirable
because casts are very powerful: they not only perform the requested
conversion, but also generally tell a C compiler to shut up and do
it no matter how wrong it looks. In other words, casts suppress
useful diagnostics. The fewer casts you use, the more likely it
is that your C compiler can catch errors in conversions. Or, to
steal a line from Stan Lee and Spider-Man, "with great power comes
great responsibility" . :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://67.40.109.61/torek/index.html (for the moment)
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 13 '05 #7
On 16 Nov 2003 18:38:21 -0700, Chris Torek <no****@elf.eng .bsdi.com>
wrote in comp.lang.c:
"Richard Heathfield" <do******@addre ss.co.uk.invali d> wrote in message
news:bp****** ****@titan.btin ternet.com...
... you don't need a cast. You can assign a void * to a char * without
casting.

On Sun, 16 Nov 2003 22:53:55 -0000, "Alex Fraser" <me@privacy.net >
wrote in comp.lang.c:
Indeed, and the reverse. In fact, all the conversions are to/from void *, so
there's no casting at all.


In article news:di******** *************** *********@4ax.c om
Jack Klein <ja*******@spam cop.net> writes:
No, this is not true. In some cases there is a difference between
casting between a pointer to void and a pointer to some non-character
object type, although not on today's common desktop systems. ...


[more about byte vs non-byte pointers, snipped]

I do not believe this is what Alex Fraser meant.


You're absolutely right, I read something in Alex's post that wasn't
actually written there. I'm not sure how I managed to do that, but
thanks for pointing it out!

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
Nov 13 '05 #8
Alex Fraser wrote:
"Hallvard B Furuseth" <h.b.furuseth(n ospam)@usit.uio (nospam).no> wrote in
message news:HB******** ******@bombur.u io.no...
Alex Fraser wrote:[snip]
However, generic functions like qsort() and bsearch() must in essence
do exactly this,


No, what these functions do to compare the objects [...]


Sorry, but you totally missed the point, which was the implementation. The
cast sequence I described seems unavoidable.


Read my article again. I explained that you were wrong, and why.
For an equivalent to qsort() (for example), the first cast happens
before you call it, the middle two within it (with the pointer
arithmetic inbetween), and the last in the comparison function.


Not so. Look at my example using qsort: No pointer arithmetic. No
casts to or from char*. If you disagree, test and then post actual
code which does what you said above, so we can see what you mean.

If you want to _implement_ qsort, you need to cast to char* and do
pointer arithmetic on the result. If you want to _use_ it, you almost
certainly need not.

--
Hallvard
Nov 13 '05 #9
In <HB************ **@bombur.uio.n o> Hallvard B Furuseth <h.b.furuseth(n ospam)@usit.uio (nospam).no> writes:
Alex Fraser wrote:
"Hallvard B Furuseth" <h.b.furuseth(n ospam)@usit.uio (nospam).no> wrote in
message news:HB******** ******@bombur.u io.no...
Alex Fraser wrote:

[snip]
However, generic functions like qsort() and bsearch() must in essence
do exactly this,

No, what these functions do to compare the objects [...]


Sorry, but you totally missed the point, which was the implementation. The ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ cast sequence I described seems unavoidable.


Read my article again. I explained that you were wrong, and why.
For an equivalent to qsort() (for example), the first cast happens
before you call it, the middle two within it (with the pointer
arithmetic inbetween), and the last in the comparison function.


Not so. Look at my example using qsort: No pointer arithmetic. No
casts to or from char*. If you disagree, test and then post actual
code which does what you said above, so we can see what you mean.

If you want to _implement_ qsort, you need to cast to char* and do
pointer arithmetic on the result. If you want to _use_ it, you almost
certainly need not.


Are you reading impaired, or what? He explicitly told you that he was
talking about the *implementation * of qsort and bsearch and, as you
agree, the casts are unavoidable. So, where is he wrong?

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 13 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
3133
by: Xavier Decoret | last post by:
This is a compiler error that I get when I try to do: void* p; unsigned int stride; // ... p += stride; I have good reason to do this, namely an iterator over an array of object whose type may vary, as outlined below. So I don't understand why
3
21036
by: Martijn | last post by:
Hi, I am looking over some of my old implementations. One of them has an "array" of void pointers defined as a pointer to the first element (without getting stuck on nomenclature, I am aware of the difference between a pointer and an array). This pointer in effect is a pointer to a void pointer: void**. But iirc, this is not entirely valid and may become a problem when dereferencing and doing pointer arithmetic. And in all honesty,...
2
1728
by: Xiangliang Meng | last post by:
Hi, all. As far as I know, the speical arithmetic operator on void pointer is an externsion in GNU CC. However, I could not find the relative topics in C99. Would someone like to help me find them out? in linux\mm\Slab.c, typedef struct slab_s { struct list_head list; unsigned long colouroff;
188
17378
by: infobahn | last post by:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
26
7768
by: Alfonso Morra | last post by:
Hi, I'm getting a compiler error of "pointer truncation from 'void *' to 'int'" because I'm not explicitly casting from void* to (datatype*). Pointers are stored as ints (is that right?), so as AFAIK, there is nothing to worry about is there? I'm using VC 7.1 Why are such assignments being treated as errors?
27
8962
by: Erik de Castro Lopo | last post by:
Hi all, The GNU C compiler allows a void pointer to be incremented and the behaviour is equivalent to incrementing a char pointer. Is this legal C99 or is this a GNU C extention? Thanks in advance. Erik
14
3017
by: arun | last post by:
Hi, Why sizeof operator when applied on void returns one when compiled with gcc compiler ??. When i tried it on VC++ compiler, it gives an error. But another version of the VC++ compiler on my friend's machine gives it as zero. Have anyone tried this ? I believe it should give an error because i think there is nothing called void. Regards, arun..
6
13725
by: Angus | last post by:
I am using a global which is a void* I have it defined in one file as: void* hFlag; and one other header file as: extern void* hFlag; But I get this compile error:
160
5648
by: raphfrk | last post by:
Is this valid? int a; void *b; b = (void *)a; // b points to a b += 5*sizeof(*a); // b points to a a = 100;
0
8863
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9384
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9238
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
6681
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5995
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4502
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3207
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2602
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2147
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.