Why multiplication not allowed?

  • Thread starter Vijay Kumar R Zanvar
  • Start date
G

glen herrmannsfeldt

pete said:
glen herrmannsfeldt wrote:
(previously snipped discussion)
(snip)
That last line of code is a syntax error.

Yes. As the pointers have different units it wouldn't make
sense even though the overall relocation factor is 1.

Also, C requires pointer comparison, and I believe pointer
subtraction to be done with pointers to the same object.
Systems that keep track of memory in a segment/offset or
object reference/offset into object usually do pointer
subtraction only subtracting the offsets. Also, the
operators <, <=, >, >= usually only apply to the offset.

For a flat address space and only (char*) pointers you
might get the same result, with other pointer types or
other addressing methods you don't.

-- glen
 
G

glen herrmannsfeldt

Christopher Benson-Manica wrote:
In that case,
struct p {
char *foo;
char bar;
int:3 baz;
int:2 quux;
};

would likely be quite a challenge to sqrt(). A lot of work for
implementors, certainly...

Well, C in general doesn't do array or struct expressions. At some
point in C history the ability to pass a struct as a function argument
was added (instead of only struct pointers).

I don't believe PL/I will do sqrt() on a pointer variable, and
I wouldn't want to see the result if it did. The rest should
be fine, though. PL/I has character string variables instead
of character arrays, and will convert between them and numeric
values, as needed.

How about a C for loop such as:

char s[100];
for(strcpy(s,"1"); strcmp(s,"100")<0; sprintf(s,"%3d",atoi(s)+1)) ;

-- glen
 
A

Arthur J. O'Dwyer

How about a C for loop such as:

char s[100];
for(strcpy(s,"1"); strcmp(s,"100")<0; sprintf(s,"%3d",atoi(s)+1)) ;

assert(0 == strcmp(s, "2"));

[Whoops.]

-Arthur
 
K

Keith Thompson

Sean Kenwrick said:
This interview was quite a long time ago (1989), but I remember it well
because of these 'trick' questions that I was asked about C. Perhaps they
were still using a compiler at the company that supported this old
syntax....

That's quite possible. In that case, the "=+" syntax and the
ambiguities it can introduce are certainly something you would have
needed to know for the job -- but it would have made a lot more sense
for them to just tell you about it, rather than expecting you to know
about it in the first place.

<OT>
On the other hand, diplomacy is also a valuable job skill.
</OT>
 
K

Keith Thompson

Dik T. Winter said:
Actually the high order 16 bits. The low order 48 bits are the memory
address.

I just ran an experiment on a Cray SV1. For a char* pointer, the
3-bit byte offset is in the high-order 3 bits of the 64-bit word.
I can believe, though, that the word address occupies only the 48
low-order bits, and the other 13 bits are always zero.

It's tempting to suggest that it would have made more sense to use the
entire upper 16 bits as a byte offset, but I suppose it's no more
difficult to extract the high-order 3 bits than to extract the
high-order 16 bits.

Here's the program:
========================================
#include <stdio.h>

int main(void)
{
char buf[100];
int i;

for (i = 0; i <= 8; i ++) {
printf("buf+%d = [%022p]\n", i, (void*)(buf + i));
}
return 0;
}
========================================

Here's the output:
========================================
buf+0 = [0000000000000000107531]
buf+1 = [0200000000000000107531]
buf+2 = [0400000000000000107531]
buf+3 = [0600000000000000107531]
buf+4 = [1000000000000000107531]
buf+5 = [1200000000000000107531]
buf+6 = [1400000000000000107531]
buf+7 = [1600000000000000107531]
buf+8 = [0000000000000000107532]
========================================

The "%p" conversion specifier formats addresses in octal. I used
"%022p" to make everything line up nicely; I'm not sure how portable
it is, but it works here.
None at all. There is *no* hardware support for 8 bit quantities.

Thanks, that's an interesting thing to know. I tried looking at an
assembly listing to figure out how the operations are implemented, but
Cray's assembler syntax is a bit odd, and I've never taken the time to
learn it.
This would be with Cray's C compiler. I do not know whether there is gcc
support for the Cray. It would be a bit foolish to look for gcc on the
Cray as it certainly does not support vectorisation.

Right, but not everything that runs on a Cray uses vectorization.
There's an entire Unix-like operating system with all the usual
utilities. But porting gcc to Cray vector machines, even without
vector support, apparently is more work than anyone has been willing
to do. (Since I'm not willing or able to do the work myself, I'm
certainly not criticizing anyone else for not doing it.)

There's also no gcc for the Cray T3E, even though it uses Alpha CPUs
rather than one of Cray's custom vector thingies.

Interesting though all this stuff is (at least to me), the only really
topical point being made is that some C implementations are weirder
than most poeple would expect. If you stick to what's guaranteed by
the standard, you can write code that's portable even to exotic
implementations. If you make implicit assumptions that happen to be
correct for every machine you've ever used (like "incrementing the
integer representation of a pointer makes it point to the next byte in
memory"), you can get into trouble.

(Arguably, it would actually have made a lot more sense for Cray's C
implementation to have CHAR_BIT==64, but that would have broken a lot
more existing software than the funny byte pointers did. I doubt that
the Unix port would have been as successful.)
 
K

Keith Thompson

Christopher Benson-Manica said:
1) p+5 and p+5*sizeof(*p) are valid constructions, correct?

Yes, but they have different meanings (unless sizeof(*p) happens to be 1).
2) I assume they do not compare as equal because of some implicit
conversion issues?
3) If 2, would you care to elaborate?
4) If 2 and 3, can you tell me what the Standard says...?

No, there's no implicit conversion, it's just the way pointer arithmetic
is defined.

C99 6.5.5 "Multiplicative operators", paragraph 8:

When an expression that has integer type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If
the pointer operand points to an element of an array object, and
the array is large enough, the result points to an element offset
from the original element such that the difference of the
subscripts of the resulting and original array elements equals the
integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N
(equivalently, N+(P)) and (P)-N (where N has the value n) point
to, respectively, the i+n-th and i-n-th elements of the array
object, provided they exist. Moreover, if the expression P points
to the last element of an array object, the expression (P)+1
points one past the last element of the array object, and if the
expression Q points one past the last element of an array object,
the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to
elements of the same array object, or one past the last element of
the array object, the evaluation shall not produce an overflow;
otherwise, the behavior is undefined. If the result points one
past the last element of the array object, it shall not be used as
the operand of a unary * operator that is evaluated.
5) Does 5+p have the same semantics as p+5?

Yes, addition is commutative. (Note that C addition is commutative
because the standard says so; it could as easily have said that
pointer+integer is legal, but integer+pointer is not. That would also
have made silly things like 5["abcdef"] illegal; see question 6.11 in
the C FAQ.)
 
C

Clark Cox

August Derleth said:
I'm not saying it would be. I'm just saying that some languages allow
it, and that I'm surprised that C isn't one of them.

If something cannot possibly be meaningful, then why would you want
to be able to write code that does it?
 
D

Dik T. Winter

> I believe PL/I will let you take the square root of a struct, doing it
> element by element. You can also take the square root of a character
> string if it has a numeric value.
>
> I wonder why C doesn't allow that.

I think numerical mathematicians would complain when the struct is
called "complex".
 
D

Dik T. Winter

>
> I just ran an experiment on a Cray SV1. For a char* pointer, the
> 3-bit byte offset is in the high-order 3 bits of the 64-bit word.
> I can believe, though, that the word address occupies only the 48
> low-order bits, and the other 13 bits are always zero.

O well, I must have disremembered. Anoyhow the other 13 bits are always
zero.
> It's tempting to suggest that it would have made more sense to use the
> entire upper 16 bits as a byte offset, but I suppose it's no more
> difficult to extract the high-order 3 bits than to extract the
> high-order 16 bits.

Indeed, no problem.
>
> Thanks, that's an interesting thing to know. I tried looking at an
> assembly listing to figure out how the operations are implemented, but
> Cray's assembler syntax is a bit odd, and I've never taken the time to
> learn it.

I never thought Cray assembler a bit odd. I have programmed quite a bit
in it. It reminds one of the assembler for the CDC 7600. Not so much of
a surprise.
>
> Right, but not everything that runs on a Cray uses vectorization.
> There's an entire Unix-like operating system with all the usual
> utilities.

Yup, I have used it.
> But porting gcc to Cray vector machines, even without
> vector support, apparently is more work than anyone has been willing
> to do. (Since I'm not willing or able to do the work myself, I'm
> certainly not criticizing anyone else for not doing it.)

Porting any untility to the Cray is much work. I have helped somebody
port a derivate of the Bourne shell to the Cray. I have ported the
Korn shell to it. Not entirely simple. The main reason being that
they assumed non-portable things (like being able to use the low
order bit of an int pointer as a flag).
> There's also no gcc for the Cray T3E, even though it uses Alpha CPUs
> rather than one of Cray's custom vector thingies.

There probably is one, but it will use only one processor. I would
think that the plain Alpha gcc would work.
> Interesting though all this stuff is (at least to me), the only really
> topical point being made is that some C implementations are weirder
> than most poeple would expect.

There are (were) weirder machines available. DG's MV series...
> (Arguably, it would actually have made a lot more sense for Cray's C
> implementation to have CHAR_BIT==64, but that would have broken a lot
> more existing software than the funny byte pointers did. I doubt that
> the Unix port would have been as successful.)

I think the software would have broken just as much. I understand the
Unix port has been a nearly complete rewrite of almost all utilities.
 
V

Vijay Kumar R Zanvar

In that case,

struct p {
char *foo;
char bar;
int:3 baz;
int:2 quux;
};

Is this a valid declaration of bit-field members?
Should it not have been

struct p {
char *foo;
char bar;
int baz :3;
int quux :2;
};
 
K

Keith Thompson

Dik T. Winter said:
I never thought Cray assembler a bit odd. I have programmed quite a bit
in it. It reminds one of the assembler for the CDC 7600. Not so much of
a surprise.

Well, it's odd compared to the assembler syntaxes I'm familiar with.

[...]
Porting any untility to the Cray is much work. I have helped somebody
port a derivate of the Bourne shell to the Cray. I have ported the
Korn shell to it. Not entirely simple. The main reason being that
they assumed non-portable things (like being able to use the low
order bit of an int pointer as a flag).

It depends on the utility, I suppose. I've recompiled quite a few
things on Crays without too much difficulty, but probably quite a few
of them had already been ported (sometimes with masses of #ifdefs).

One example: as far as I know, Perl compiles out of the box.

[...]
I think the software would have broken just as much. I understand the
Unix port has been a nearly complete rewrite of almost all utilities.

Hmm, that's surprising.
 
G

glen herrmannsfeldt

Arthur said:
How about a C for loop such as:

char s[100];
for(strcpy(s,"1"); strcmp(s,"100")<0; sprintf(s,"%3d",atoi(s)+1)) ;


assert(0 == strcmp(s, "2"));

[Whoops.]

I presume you didn't run the loop, though you don't say the
results of the assert.

The "%3d" is important to make it work, along with a character
set where ' ' < '1'.

-- glen
 
A

Arthur J. O'Dwyer

char s[100];
for(strcpy(s,"1"); strcmp(s,"100")<0; sprintf(s,"%3d",atoi(s)+1)) ;

assert(0 == strcmp(s, "2"));

[Whoops.]

I presume you didn't run the loop, though you don't say the
results of the assert.

The "%3d" is important to make it work, along with a character
set where ' ' < '1'.

Hmm... if it weren't for that last assumption, I'd have to say
"move that Whoops down two levels of quotation." :( But you could
actually fix the code, couldn't you, by changing "%3d" to "%03d".
Then it would work no matter what value your system gave to ' '!

atoi("010") == 10, right? What standard functions treat "010"
as octal? Could someone with a fast connection and 'grep' please
give a list of those circumstances? (I think there's some 'scanf'
format that understands 0x and 0, isn't there?)

-Arthur
 
K

Kevin Goodsell

Arthur said:
atoi("010") == 10, right? What standard functions treat "010"
as octal? Could someone with a fast connection and 'grep' please
give a list of those circumstances? (I think there's some 'scanf'
format that understands 0x and 0, isn't there?)

%i does for scanf. The various strto* functions can also, if you give
them a base of 0.

-Kevin
 
K

Kevin Goodsell

Kevin said:
%i does for scanf. The various strto* functions can also, if you give
them a base of 0.

Also: atoi always uses base 10 (as if calling strtol() with 10 as the
base argument), so your first statement is correct.

-Kevin
 
D

Dik T. Winter

>
> Well, it's odd compared to the assembler syntaxes I'm familiar with.

Ah, I know stranger syntaxes than Cray's. Here a short routine that sets
the register at 1 when the current value >= +0 and to -1 when it is <= 0:
F = F, P
Y, F = 1
N, F = -1
The keyword syntax as you know it is one of the many syntaxes around.
>
> It depends on the utility, I suppose. I've recompiled quite a few
> things on Crays without too much difficulty, but probably quite a few
> of them had already been ported (sometimes with masses of #ifdefs).

It also depends on the time-span. When Cray started developing Unicos
(early 1990's I think), there was not yet really much consideration for
portability in the source of utilities. Especially to machines that
were not Vax lookalikes.

> One example: as far as I know, Perl compiles out of the box.

Probably. Currently utilities are much better programmed. But I know
that (for instance) wuftpd will not work out of the box on a machine
where the bit pattern of the null pointer is not all zero bits and
NULL is defined as (void *)NULL. However, currently there are still
utilities that assume that if you cast a pointer to char to a pointer
to int and back again to a pointer to char, this may fail (and not
only on the Cray, but with the C compiler I used on the Cray it would
certainly fail). And there is still software around that makes this
assumption. (Of course it would also fail on a DG MV.) On the other
hand, compiling out of the box does *not* mean that it will work.
>
> Hmm, that's surprising.

Not so very much. When Unicos was started, portability of source in C
was still in its infancy. Take the source for the Bourne shell for
instance. It would compile out of the box, but it would not work at
all (its memory allocation and deallocation routines would fail amongst
other problems %). There were too many utilities where the source assumes
something special about the machine which is false on a slightly esoteric
architectures. Getting Unix and all utilities to work on a 80286 also
has taken quite some rewriting, I understand.
(And there still are.)
-
% The Korn shell I ported to the Cray had no longer these problems, because
there were #ifdefs for the Cray in the source. I no longer have the source
available, but if I remember correctly, there were quite a few. However,
many of those #ifdefs would not have been needed if portability had been
the first concern.
 
G

glen herrmannsfeldt

(snip of for loop using strings)
Hmm... if it weren't for that last assumption, I'd have to say
"move that Whoops down two levels of quotation." :( But you could
actually fix the code, couldn't you, by changing "%3d" to "%03d".
Then it would work no matter what value your system gave to ' '!
atoi("010") == 10, right? What standard functions treat "010"
as octal? Could someone with a fast connection and 'grep' please
give a list of those circumstances? (I think there's some 'scanf'
format that understands 0x and 0, isn't there?)

I wasn't too worried, ' '<'1' in both ASCII and EBCDIC.

Anyway, with the right number of blanks, you can do this with
a PL/I DO statement.

DCL S CHAR(100) VARYING;
DO S='1' TO ' 100' BY '1';
PUT SKIP LIST(SQRT(S));
END;

-- glen
 
P

Peter Pichler

Keith Thompson said:
Not many years ago, I used a compiler (VAXC, I think) that allowed the
old =+ syntax, but I think it at least issued a warning about it.

We still use one at my work. There used to be a lot of places in the code
that looked like this:

something =NULL;
other =NULL;
whatever =&something_else;

Please note lots of spaces before '=' but none after it. It was the
prefered style of the programmer who wrote it. After the warnings, she
corrected ti to:

something =NULL;
other =NULL;
whatever =(&something_else);

;-)
 
P

Peter Pichler

glen herrmannsfeldt said:
I have used compilers that allowed them for compatibility. I still
always put a space between = and -, like i= -1; to be sure.

I always use spaces around *all* binary (or ternary) operators.
For clarity.

So,
i = -1;
a = m * n + 4;
etc.

But I appreciate that it's just a matter of style.

Peter
 
P

Peter Pichler

Eric Sosman said:
The result would be meaningless. An easy (but
informal) way to understand this is to use an analogy:
think of pointer values as street addresses. Then
the following operations make sense:

- Similarly, computing "123 Main Street times
89 El Camino Real" makes no sense. Perhaps the
result might be considered a kind of "area,"
but there seems to be no useful analogous
concept to "area" in the addressing of memory-
resident objects.

No, it could not be an area. For two reasons:
1. Where is a guarante that Main Street and El Casino Real are
perpendicular? What if they are parallel? Or even in two different towns, or
even countries?
2. Even if they were perpendicular, you would need a range on each side, so
perhaps "123 to 234 Main Street times 89 to 98 El Camino Real", which boils
down to multiplication of integers ;-)

The upshot is, Ben was right.

Peter
 

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
474,135
Messages
2,570,783
Members
47,341
Latest member
hanifree

Latest Threads

Top