Re: large files: when ubiquitous?

From: P.T. Breuer (ptb_at_oboe.it.uc3m.es)
Date: 05/08/04


Date: Sat, 08 May 2004 15:20:12 GMT

Kasper Dupont <kasperd@daimi.au.dk> wrote:
> "P.T. Breuer" wrote:
> >
> > It says reading anything from a char* is always OK (as far as I can
> > make out), but I would disagree - surely a char* can have any
> > alignment? Not necessarily one that matches the alignment of the
> > type you want to read.
>
> The discussion is not about alignment at all. It is about
> optimizations performed by the compiler. If you have a
> pointer to a float, and another pointer to a long, the
> compiler may assume chaning the one would not change the
> other.

The compiler can safely make no optimization assumptions at all on an
indirection in C. Just to be silly, the pointer might be into shared
memory - you're not then even the only thread with access.

It's only safe when you can prove that no other functional unit has
write access there, which is nearly freaking impossible in C.

> Eg. this program print 1078523331 when compiled without
> optimization, and print 42 when compiled with -O3
>
> #include <stdio.h>
> #include <stdlib.h>
> long f(long *a, float *b)
> {
> *a=42;
> *b=3.14;
> return *a;
> }

Oh great. When both addresses are the same one or the other write wins.

Well, as you can see, it's not safe to elide the *b = 3.14 here.
Compiler mistake if it does. Send in bug report. Rewrite code for f as
inline local function using parents variables, or macro.

> int main()
> {
> void *p=malloc(42);
> printf("%ld\n",f(p,p));

Hmm. You don't seem to object to void* there! As I said below, at least
void* is a contractural promise that it's 4-aligned. Making promises is
a good thing, in general, imo.

If we pass char* instead to f, then we would be implictly saying that we
don't guarantee to f that its parameters in this instance are even
aligned the way f's prototype says they should be, which in my opinion
ought to generate a compiler warning.

Yet the info page seems to say that passing char* turns off "type
punning" checks.

   The practice of reading from a different union member than the one
   most recently written to (called "type-punning") is common. Even
   with `-fstrict-aliasing', type-punning is allowed, provided the
   memory is accessed through the union type.

   ...

   For example, an `unsigned int' can alias an `int', but not a `void*'
   or a `double'. A character type may alias any other type.

(I'm not absolutely sure what they meant in the last, but I think they
mean to refer to char*, where "character type" refers to the content of
the indirection).

So do you think the compiler will warn you about type punning in your
example?

> return 0;
> }
>
> > Wouldn't reading "anything" from a void* be safer?
>
> Dereferencing a void shouldn't be allowed at all.

Nobody does - they cast the address to (other*) first. I meant

     int *x = (void*)silly_address;

There is no read of a void.

> The reason a char pointer is not assumed to point at
> different address than any other pointer is, that you
> can do stuff like reading, writing, copying data of
> any type by using a char pointer.
>
> > It's certainly common in the kernel to pass foo(void *data)
> > and then at the receiving end read mystruct *x = data;
>
> But by the time you derefernce the pointer it is no
> longer a void pointer,

Nor is there when you read "anything" from a void*.

> so the discussion about type
> punning doesn't apply at all.

Then what ARE we talking about? I'll try and look up some debian type
punning warning reports of mine ..

 In function `masterpropagate':
 2732: warning: dereferencing type-punned pointer will break strict-aliasing rules
 2734: warning: dereferencing type-punned pointer will break strict-aliasing rules

          int i;
          int pid;
          struct d_db * spids_db = &self->spids;

          for (
***** i = spids_db->first(spids_db, (void**)&pid,NULL);
              i >= 0;
***** i = spids_db->next (spids_db,i,(void**)&pid,NULL)
          ) {

and the methods are of type

   int (*first)(struct d_db * self, void **nam, void **val);
   int (*next) (struct d_db * self, int i, void **nam, void **val);

The calls match the prototypes. What is it complaining about?

> Actually that variable
> might as well have been passed as a char pointer. It

Ah.

> would be ugly, but it would work exactly the same.

Well, char* seems to be the only way to avoid complaints, according to
info. Whether you want to avoid it is another matter.

Peter



Relevant Pages

  • Re: Micro-C -- Help monitoring a switch on 8051
    ... > pushed" should be displayed in the LCD. ... Hopefully, this is a standard compliant C compiler, otherwise you won't ... char ScanKeypad(void); ...
    (comp.lang.c)
  • Re: Passing void pointer to p_thread that is a Char
    ... > integer of a different size (char). ... > user-defined start routine. ... > pointer to this start routine (a function that takes a single void* ...
    (comp.lang.c)
  • Re: Common misconceptions about C (C95)
    ... malloc returns a pointer to void - and that is a generic pointer ... There is a rule you should learn: never ever cast except you KNOWs ... It doesn't have the implicit conversion from void * to any object type, ... not simply a char* but a pointer with unknow type. ...
    (comp.lang.c)
  • Re: is there a way to do this...
    ... >>void change ... i is a pointer to int, and on this platform, consumes a place in a ... This defines ptr to be a pointer to characters, ... the compiler intended us to go. ...
    (comp.lang.c)
  • Re: Vancouver Lisp Users Group meeting for February 2008 - Doing Evil Things with CL
    ... pointer points to a single element or a vector (and whether the vector ... ==> p must be a pointer to a null terminated vector of char. ... extern void glDrawElements(GLenum mode, GLsizei count, GLenum type, ... Run time type errors in Lisp are usually easy to find and fix. ...
    (comp.lang.lisp)