What is const char * const *p;

  • Thread starter Vijay Kumar R. Zanvar
  • Start date
V

Vijay Kumar R. Zanvar

Hello,

I have few questions. They are:

1. Is "const char * const *p;" a valid construct?
2. How do I align a given structure, say, at 32-byte boundary?
3. Then, how do I assert that a given object is aligned, say,
at 32-byte boundary?


Regards,
 
E

E. Robert Tisdale

Vijay said:
I have few questions.

1. Is "const char* const *p;" a valid construct?

Yes. Both p and the char to which p ponts are const.
2. How do I align a given structure, say, at 32-byte boundary?

char* q = (char*)malloc(64);
char* p = (q + 31)&(~31);

p is aligned on a quad word boundary.

3. Then, how do I assert that a given object is aligned, say,
at 32-byte boundary?

assert(p == ((p + 31)&(~31)));
 
R

Richard Bos

1. Is "const char * const *p;" a valid construct?
Yes.

2. How do I align a given structure, say, at 32-byte boundary?
3. Then, how do I assert that a given object is aligned, say,
at 32-byte boundary?

You don't, and you can be reasonably but not perfectly sure,
respectively.

That is, if you happen to _know_ that a certain C type must be aligned
on 32-byte boundaries, then you also know that both all actual objects
of that type are indeed so aligned, and that so is the memory you get
from malloc() (because that must be correctly aligned for any type,
including your 32-byte one).
The problem is finding a type like that, because nothing in the Standard
demands anything about the alignment of any type except that several
kinds of types must have the same alignment as closely related types
(e.g., signed and unsigned int must be identically aligned; void * has
the same requirements as char *; etc.) and that malloc() returns an
all-suitable pointer. There is nothing that either demands that a
certain type is aligned to certain boundaries, or that allows you to
find out which alignment requirements a type has.
Oh, one exception: because array members are contiguous, all types can
have no stricter alignment requirements than to sizeof(type). But since
they could also be aligned more loosely (say, to half of sizeof(type)),
this doesn't actually help you any if you really need an alignment of a
particular strictness. In particular, any object of type struct align {
char align[32]; } is not guaranteed to be aligned on a 32-byte boundary,
or indeed any boundary at all.

As for asserting the alignment of an existing object, you can try to
check that ((intptr_t)&object)%32 (or if you use C89, ((unsigned
long)&object)%32) is zero. This is not strictly required to work, since
conversion from pointers to integers is implementation-defined, but it
would not be unreasonable to assume that on all modern implementations,
this does in fact work as expected - if only because the implementor
would have to go out of his way to make it fail. So expect it to fail
quite spectacularly on the DS9K <g>, but not on any common system.

Richard
 
C

Charlie Gordon

E. Robert Tisdale said:
Vijay Kumar R. Zanvar wrote a bit hastily:


Yes. Both p and the char to which p ponts are const.

No! p points to a constant pointer to constant chars. You can change p, but
you cannot change the pointer it points to, not the characters this pointer
points to.
char* q = (char*)malloc(64);
char* p = (q + 31)&(~31);

p is aligned on a quad word boundary.

quad word ? what is the size of a word ? are you mixing bits and bytes ?
The above code will not compile on a decently configured compiler because it
does implicit conversions between integers and pointers. you can use this
instead:

unsigned char *q = malloc(32 + 31);
void *p = (void*)(((unsigned long)q + 31) & ~31);

But it not portable code either. On a C99 conformant environment, you may use
intptr_t instead of unsigned long to allow for pointers with a different size
than long, but the arithmetic trick played is not guaranteed to have the
required effect on pointer alignment on all architectures.
assert(p == ((p + 31)&(~31)));

Same remark : implicit conversions between pointer and integer.
With the restrictions expressed above, use this:

assert(((unsigned long)p & 31) == 0);
 
C

Chris Croughton

char* q = (char*)malloc(64);
char* p = (q + 31)&(~31);

p is aligned on a quad word boundary.

That is undefined behaviour in standard C:

6.5.10 Bitwise AND operator

Constraints
2 Each of the operands shall have integer type

How do you know that the (int) value (~31) is wide enough to bitwise and
with a pointer to give meaningful results?

In C99 you could write:

#include <stdint.h>

...

void *q = malloc(64);
intptr_t pq = ((intptr_t)q + 31) & (~31);
char *p = (char*)pq;

However, although the standard guarantees that an intptr_t is a "signed
integer type with the property that any valid pointer to void can be
converted to this type, then converted back to pointer to void, and the
result will compare equal to the original pointer", it does not
guarantee that the result after doing arbitrary arithmetic operations on
the type will still convert back to a valid pointer. For instance, a
pointer to character could be defined on a hypothetical machine as:


+-+-+-+-+- ... -+-+
| b | word-ptr |
+-+-+-+-+- ... -+-+

Where 'word-ptr' is the pointer to a 32 bit word and 'b' an 8-bit byte
reference within the word. Pointer arithmetic on T* would manipulate it
appropriately (if sizeof(T) were a multiple of 4 bytes then it would be
simple, otherwise the compiler would have to shift bits around), but
casting to an intptr_t and anding with ~31 would produce a very wrong
result.

Unlikely, certainly, but nothing in the standard forbids it.
assert(p == ((p + 31)&(~31)));

The same applies.

In my own code I have assumed that malloc() is standard-compliant and
returns an area of memory which is "suitably aligned so that it may be
assigned to a pointer to any type of object and then used to access such
an object or an array of such objects in the space allocated" (section
7.20.3), and then have made sure that if I subdivide it I do so in sizes
also aligned to the worst case.

Note that since arrays of objects are contiguous, any object need only
be aligned to its own size (or rather the size of the biggest builtin
type in the object if it is an aggregate) as a worst case. Unless you
are doing some system-dependant thing which needs a special alignment
(for instance using hardware-accessed buffers).

Chris C
 
D

Dan Pop

In said:
That is undefined behaviour in standard C:

6.5.10 Bitwise AND operator

Constraints
2 Each of the operands shall have integer type

A constraint violation is not undefined behaviour. Basically, it means
that this is not standard C code and the compiler must diagnose it,
while undefined behaviour need not be diagnosed.

Dan
 
C

CBFalconer

E. Robert Tisdale said:
Vijay Kumar R. Zanvar wrote:
.... snip ...


assert(p == ((p + 31)&(~31)));

Undefined behaviour. This is an operation that can only be
performed outside the C language, and is non-portable.
 
D

Dan Pop

In said:
1. Is "const char * const *p;" a valid construct?

Yes, of course.
2. How do I align a given structure, say, at 32-byte boundary?

You cannot do that portably in C.
3. Then, how do I assert that a given object is aligned, say,
at 32-byte boundary?

Ditto.

The best you can do in C is converting pointers to (unsigned) integers,
adjust the integers so they become multiples of the desired alignment and
then convert them back to pointers. Alignment checking is performed the
same way.

Here's some sample C89 code that may or may not work (it works on all
mainstream implementations):

struct struct32 { ... } *p;
char buff[sizeof(struct struct32) + 31];
unsigned long addr = (unsigned long)buff, tmp;

p = (struct struct32 *) (addr + ((tmp = addr % 32) ? 32 - tmp : 0));
if ((unsigned long)p % 32 == 0) /* p is aligned */ ;

When the desired alignment is a power of 2, the % operator can be replaced
by bitwise operations, but the code becomes less readable.

Dan
 
D

Dan Pop

In said:
Undefined behaviour.

Can I have the chapter and verse? I always thought it was a constraint
violation:

6.5.10 Bitwise AND operator

Syntax

1 AND-expression:
equality-expression
AND-expression & equality-expression

Constraints

2 Each of the operands shall have integer type.
This is an operation that can only be performed outside the C language,

Wrong again: it can be performed without violating the C language
specification, by converting the pointer to a suitable integer type.
and is non-portable.

This is correct, in theory, at least.

Dan
 
C

CBFalconer

Dan said:
Can I have the chapter and verse? I always thought it was a
constraint violation:

6.5.10 Bitwise AND operator

Syntax

1 AND-expression:
equality-expression
AND-expression & equality-expression

Constraints

2 Each of the operands shall have integer type.


Wrong again: it can be performed without violating the C language
specification, by converting the pointer to a suitable integer type.


This is correct, in theory, at least.

Thanks for the corrections. However the theme of my reply "Tisdale
is in serious error again" still holds, together with "don't do
that". Even if the conversions work, there is no guarantee that
any such results indicate anything whatsoever about alignment.
 
D

Dan Pop

In said:
that". Even if the conversions work, there is no guarantee that
any such results indicate anything whatsoever about alignment.

This is a quality of implementation issue and you won't find many
implementors foolishly ignoring it. If the standard allows such
conversions, it is because they are the ONLY *reasonably* portable
solution to this class of problems.

Dan
 
T

Tim Rentsch

CBFalconer said:
Undefined behaviour. This is an operation that can only be
performed outside the C language, and is non-portable.

A technical detail here, but one that I think is important.

The operation can be performed inside the C language. It's
just that it produces undefined behavior when it does.

The flip side of that view seems, well, at least unuseful. Otherwise,
we'd have to say that any program that dereferences a NULL pointer
isn't a C program. Whether something is written in the C language
should be something that can be determined statically. Of course, it
may be true that executing a C program produces undefined behavior,
but it's still C.
 
K

Keith Thompson

Tim Rentsch said:
A technical detail here, but one that I think is important.

The operation can be performed inside the C language. It's
just that it produces undefined behavior when it does.

The operation being attempted can be performed inside the C language,
but not the way ERT presents it. The bitwise "&" operator cannot
legally be applied to a pointer value. It's a constraint violation,
not merely undefined behavior.

Incidentally, I've worked on systems where you can't determine the
alignment of a pointer value just by examining its low-order bits.
 
T

Tim Rentsch

Keith Thompson said:
The operation being attempted can be performed inside the C language,
but not the way ERT presents it. The bitwise "&" operator cannot
legally be applied to a pointer value.

Right. Of course what I meant was that the operation of testing a
pointer for alignment can be (non-portably) performed by using an '&'
operation. There does need to be a cast of the pointer to perform
the '&' operation.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,404
Latest member
PerryRutt

Latest Threads

Top