Get pixel value ...more in details

Example:
p[0] = 10101010
p[1] = 11110000
p[2] = 00001111

This becomes
000011111111000010101010
which is
00001111 11110000 10101010
(ordered with p[2] on the left through to p[0] on the right).

This is returned as a Uint32, so there will be leading zeros… the
result for this example therefore would be:
00000000000011111111000010101010 (with 8 leading zeros added)


Ben Sizer

I understand a little more…but:

  • shifting one bite by 16 or even 8 bits doesn’t always gives
    a zero value ?

  • we are returning p[2]<< a | p[1] << b | p[0] that is not*
    a Uint32 (also *p or *(Uint16 *)p are not) , so how and where
    happens this conversion ??

Stefano–@The_Spider

I understand a little more…but:

  • shifting one bite by 16 or even 8 bits doesn’t always gives
    a zero value ?

It probably should. But apparently doesn’t. I am guessing that this code
relies on implementational details, such as the compiler always
implicitly using 32 bits (or more) for temporary values of bytes. And
that this could break if the compiler chose to do it differently. But no
doubt someone will quote a paragraph from the standard explaining why I
am wrong. If you’re worried about it, put a (Uint32) cast before the
p[2] in the expression.

  • we are returning p[2]<< a | p[1] << b | p[0] that is not*
    a Uint32 (also *p or *(Uint16 *)p are not) , so how and where
    happens this conversion ??

The conversion is automatic (implicit). The compiler can perform this
kind of conversion automatically because you can’t possibly lose any
data casting up from one integral type to a larger integral type. So no
cast is needed.–
Ben Sizer

Example:
p[0] = 10101010
p[1] = 11110000
p[2] = 00001111

This becomes
000011111111000010101010
which is
00001111 11110000 10101010
(ordered with p[2] on the left through to p[0] on the right).

This is returned as a Uint32, so there will be leading zeros… the
result for this example therefore would be:
00000000000011111111000010101010 (with 8 leading zeros added)

I understand a little more…but:

  • shifting one bite by 16 or even 8 bits doesn’t always gives
    a zero value ?

Not necessarily. Compilers sometimes take the liberty of extending the
field to accommodate the new value. I don’t know what the C standard says
on this, but it doesn’t seem to be guaranteed, as I’ve had it fail on some
platforms. The SDL code seems to make this assumption a lot.

  • we are returning p[2]<< a | p[1] << b | p[0] that is not*
    a Uint32 (also *p or *(Uint16 *)p are not) , so how and where
    happens this conversion ??

Again, it’s a bad assumption that seems to work on most platforms. It will
probably fail on platforms where sizeof(int) != 4 or (possibly) the
compiler isn’t gcc. I had big problems with this when I tried to port SDL
to PalmOS (finally did get it to compile without warnings after adding a
bunch of Uint32 casts to this kind of code).

-JohnOn Sunday, August 26, 2001, at 02:35 AM, sragno at libero.it wrote:

wrote in message
news:mailman.998808066.21512.sdl at libsdl.org

  • shifting one bite by 16 or even 8 bits doesn’t always gives
    a zero value ?

Integral promotion rules. In ‘x << 8’, the right-hand side is of type
’int’, so the left hand side is promoted also promoted to ‘int’. There is
also a rule that in any expression, all types narrower than ‘int’ are
promoted to ‘int’.

  • we are returning p[2]<< a | p[1] << b | p[0] that is not*
    a Uint32 (also *p or *(Uint16 *)p are not) , so how and where
    happens this conversion ??

Since the function is defined as returning ‘Uint32’, all returned values are
converted to type ‘Uint32’ by the rules of implicit conversion. In other
words, the following two functions are semantically equivalent:

/* Let A and B be any types. */

A f(B arg)
{
return arg; /* implicit conversion here */
}

A f(B arg)
{
A result = arg; /* implicit conversion here */
return result;
}–
Rainer Deyke (root at rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor

Integral promotion rules. In ‘x << 8’, the right-hand side is of type
’int’, so the left hand side is promoted also promoted to ‘int’. There is
also a rule that in any expression, all types narrower than ‘int’ are
promoted to ‘int’.

Hmm… I don’t think we can assume “int” is as big as Int32, can we?
Perhaps the code should read:

return (Int32)p[2]<<a | (Int32)p[1]<<b | (Int32)p[0];

instead of:

return p[2]<<a | p[1]<<b | p[0];

?

Furthermore, I believe “|” is higher on the order of operations than “<<”,
so don’t we actually want:

return ((Int32)p[2]<<a) | ((Int32)p[1]<<b) | (Int32)p[0];

?

-Mark (on a high latency shell connection from Japan to US…)On Sun, 26 Aug 2001, Rainer Deyke wrote:


Mark K. Kim
http://www.cbreak.org/mark/
PGP key available upon request.

Example:
p[0] = 10101010
p[1] = 11110000
p[2] = 00001111

This becomes
000011111111000010101010
which is
00001111 11110000 10101010
(ordered with p[2] on the left through to p[0] on the right).

This is returned as a Uint32, so there will be leading zeros… the
result for this example therefore would be:
00000000000011111111000010101010 (with 8 leading zeros added)


Ben Sizer

I understand a little more…but:

  • shifting one bite by 16 or even 8 bits doesn’t always gives
    a zero value ?

Yes it does. A nicer and safer way to write such code would be something
like

int res;
char r,g,b;

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;
return res;

or

return (int)r | ((int)g << 8) | ((int)b << 16);
  • we are returning p[2]<< a | p[1] << b | p[0] that is not*
    a Uint32 (also *p or *(Uint16 *)p are not) , so how and where
    happens this conversion ??

The return type of the function has to be big enough to fit any supported
pixel format. The bits above the highest bit used are zero.

Now, the reason why the 8, 16 and 32 bit/pixel cases are different from
the 24 bit/pixel case, is that there’s no way to read a 24 bit integer
from memory(*). Instead, we read one byte at a time, and then assemble
them into one 32 bit integer, where the top 8 bits are zero.

(*) Well, not on your average CPU at least, and it’s not supported by C,
unless one of the integer types is used to represent the 24 bit word
size.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Sunday 26 August 2001 08:35, sragno at libero.it wrote:

Example:
p[0] = 10101010
p[1] = 11110000
p[2] = 00001111

This becomes
000011111111000010101010
which is
00001111 11110000 10101010
(ordered with p[2] on the left through to p[0] on the right).

This is returned as a Uint32, so there will be leading zeros… the
result for this example therefore would be:
00000000000011111111000010101010 (with 8 leading zeros added)

I understand a little more…but:

  • shifting one bite by 16 or even 8 bits doesn’t always gives
    a zero value ?

Not necessarily. Compilers sometimes take the liberty of extending the
field to accommodate the new value. I don’t know what the C standard
says on this, but it doesn’t seem to be guaranteed, as I’ve had it fail
on some platforms.

Same here.

It seems that old compilers (that don’t know that modern CPUs prefer
working with 32 bit registers for speed) frequently work by the rule
"cast as late as possible, so we can use the samllest possible word size
for each operation". On such compilers, all shifting and or:ing will be
performed on Uint8, and then the result will be extended (zero padded) to
Uint32.

The SDL code seems to make this assumption a lot.

Then again, that code isn’t meant for 8 or 16 bit CPUs, is it…? (Not an
excuse to write unsafe code, though!)

  • we are returning p[2]<< a | p[1] << b | p[0] that is not*
    a Uint32 (also *p or *(Uint16 *)p are not) , so how and where
    happens this conversion ??

Again, it’s a bad assumption that seems to work on most platforms.

Doesn’t work on Borland C++/DOS real mode! :slight_smile: (Thank God I’m supposed to
ditch it for good, in favor if gcc/g++ within less than half a year.)

It
will probably fail on platforms where sizeof(int) != 4 or (possibly)
the compiler isn’t gcc. I had big problems with this when I tried to
port SDL to PalmOS (finally did get it to compile without warnings
after adding a bunch of Uint32 casts to this kind of code).

Oops. (16 bit RISC?)

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Sunday 26 August 2001 17:40, John R. Hall wrote:

On Sunday, August 26, 2001, at 02:35 AM, sragno at libero.it wrote:

“David Olofson” <david.olofson at reologica.se> wrote in message
news:mailman.998921405.27562.sdl at libsdl.org

Yes it does. A nicer and safer way to write such code would be
something
like

int res;

Should be ‘Uint32’ (or ‘unsigned long’), otherwise it will break on 16 bit
CPUs.

char r,g,b;

Should be ‘Uint8’ or ‘unsigned char’. Signed rgb values are non-sensical.

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;

Integer promotion rules make these casts redundant. Replace ‘int’ with
’Uint32’, and they’ll be correct and no longer redundant.> return res;


Rainer Deyke (root at rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;

Integer promotion rules make these casts redundant. Replace ‘int’
with
’Uint32’, and they’ll be correct and no longer redundant.

Are these rules mandated by the Standard (and if so, is it the same for
C and C++), or are they just something that ‘most’ compilers do?
Personally I don’t see why the left value in a shift expression would be
promoted to the type of the value on the right. It makes sense for
arithmetic operators but not for shift operators. For example, where’s
the sense in having ((char)100 << (long)14) and ((char)100 << (short)14)
yielding different results?–
Ben Sizer

Yes, of course. I was somewhere else when I wrote that… heh

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Monday 27 August 2001 21:28, Rainer Deyke wrote:

“David Olofson” <david.olofson at reologica.se> wrote in message
news:mailman.998921405.27562.sdl at libsdl.org

Yes it does. A nicer and safer way to write such code would be
something
like

int res;

Should be ‘Uint32’ (or ‘unsigned long’), otherwise it will break on 16
bit CPUs.

char r,g,b;

Should be ‘Uint8’ or ‘unsigned char’. Signed rgb values are
non-sensical.

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;

Integer promotion rules make these casts redundant. Replace ‘int’ with
’Uint32’, and they’ll be correct and no longer redundant.

AFAIK, they’re mandatory, and most compilers follow them.

However, “promotion to int” means “promotion to whatever size int is on
this platform”, so it might not do what you want even if the compiler
doesn’t do anything wrong - that’s the problem here.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Monday 27 August 2001 21:54, Kylotan wrote:

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;

Integer promotion rules make these casts redundant. Replace ‘int’

with

‘Uint32’, and they’ll be correct and no longer redundant.

Are these rules mandated by the Standard (and if so, is it the same for
C and C++), or are they just something that ‘most’ compilers do?

“Kylotan” wrote in message
news:mailman.998942646.2098.sdl at libsdl.org

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;

Integer promotion rules make these casts redundant. Replace ‘int’
with
’Uint32’, and they’ll be correct and no longer redundant.

Are these rules mandated by the Standard (and if so, is it the same for
C and C++), or are they just something that ‘most’ compilers do?

I don’t have a copy of the Standard, but I can quote K&R.

The C Programming Language, Second Edition, A6.1:

 A character, a short integer, or an integer bit field, all signed or

not, […] may be used in an expression wherever an integer may be used. If
an ‘int’ can represent all the values of the original type, then the value
is converted to ‘int’; otherwise the value is converted to ‘unsigned int’.

Personally I don’t see why the left value in a shift expression would be
promoted to the type of the value on the right.

The type of the value on the right doesn’t matter in this case. Integer
promotion always happens when a type that is narrower than ‘int’ is used in
an expression.

assert(((char)1 << (char)8) == 0x100);–
Rainer Deyke (root at rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor

res = (int)r;
res |= (int)g << 8;
res |= (int)b << 16;

Integer promotion rules make these casts redundant. Replace ‘int’
with
’Uint32’, and they’ll be correct and no longer redundant.

Are these rules mandated by the Standard (and if so, is it the same for
C and C++), or are they just something that ‘most’ compilers do?
Personally I don’t see why the left value in a shift expression would be
promoted to the type of the value on the right. It makes sense for
arithmetic operators but not for shift operators. For example, where’s
the sense in having ((char)100 << (long)14) and ((char)100 << (short)14)
yielding different results?

yes - these are pretty much mandatory… (see other posts people made)

also sign extension can cause funny things… in signed char, bit 8 is the
sign bit and if you want to -keep- ranges 0x80-0xff valid you want
unsigned…

(char)100 << (sometype)14) = // thinking unusual circumstances
if kept char (or short); result = 0… or -1…
if unsigned char (or unsigned short); result’s probably 0
if promoted to int (or larger): 0x190000

and IIRC, the left is promoted to the type of the result… or was it
-always- promoted to int, then downgraded to the lvalue? I canna
remember… (gnu always promotes to int/Uint32 IIRC)

and note for fun to those folks translating from MASM-style assembly that
SHL and SAL are different (shift left and arithetic shift left) although
apparently SHR/SAR are more trouble… (referring to TASM 3.0 manual :slight_smile:
(SAL/SAR use the sign bit, SHL/SHR consider it a normal bit)

G’day, eh? :slight_smile:
- TeunisOn Mon, 27 Aug 2001, Kylotan wrote:

“John R. Hall” wrote:

Again, it’s a bad assumption that seems to work on most platforms. It will
probably fail on platforms where sizeof(int) != 4 or (possibly) the
compiler isn’t gcc. I had big problems with this when I tried to port SDL
to PalmOS (finally did get it to compile without warnings after adding a
bunch of Uint32 casts to this kind of code).

read the section about integral promotion in the standard. If you have
had it “fail on some platforms”, and it is SDL code, then please
notice us so we can check if it needs to be fixed

In this case the code makes the silent assumption that an int is at least
24 bits in size, which is mostly true for the platforms SDL was intended
to run on but since the Standard allows int to be as small as 16 bit
it is not strictly correct (widening cast is needed)

I suspect the SDL code itself trusts int to be at least 32 bits in a lot
of places (and perhaps a couple where int is assumed to be exactly
32 bits, although I have tried to minimize that myself

Sometimes compilers for 16-bit platforms allow you to specify via option
flags whether int should be 16 or 32 bit. This is especially useful
for a 16-bit implementation of a 32-bit architecture like the m68000

“Rainer Deyke” wrote:

I don’t have a copy of the Standard, but I can quote K&R.

Rainer usually knows what he is talking about but please note that
integral promotion is one of the things that changed from K&R to ANSI C89
(C89 uses value-preserving semantics for signedness of types, K&R uses
preservation of signedness. Most people believe this was one of the few
places where C89 was a change for the worse)

assert(((char)1 << (char)8) == 0x100);

keep in mind that the shift operators don’t behave exactly like the other
binary operators regarding type promotion, since the size of the shift
amount (the right hand side) doesn’t really affect the size of the result

Also note that you can buy the latest C Standard online for ANSI
in PDF format for just 18 USD. I would urge anyone taking C programming
at all seriously to get it