Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Hex numbers in C?

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Hex numbers in C?
Doctor Cop
Member #16,833
April 2018
avatar

What is this?

```
pCmp[i] ^= (rand() & 0xFF);
```

I understand that in this line its exclsive ORing pCmp[i] with a random number but what is 0xFF, its new to my. My tutorial didn't cover this.

raynebc
Member #11,908
May 2010

0xFF is the hexadecimal value for 255. Basically, ANDing a number by 255 serves to discard all of that number's value that uses more than the first 8 bits to represent (ie. limiting it to a value between 0 and 255). In this example, it's limiting the scope of the XOR operation.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

jmasterx
Member #11,410
October 2009

Audric
Member #907
January 2001

0x is the prefix for writing hexadecimal numbers (numeric literals) in source code.
It's pretty standard, should be supported by every c / c++ compiler you'll ever use.

Some more recent standards and compilers support 0b for binary, ex: 0b11011100

One gotcha of C is that one of the most ancient standards (ISO C, ANSI C ?) defines 0 as the prefix for octal numbers, so every compiler that maintains compatibility will assume that when you type 010, you mean the number eight. 012 would be ten etc. 09 should raise a syntax error, since 9 is not an digit in octal.
A lot of coders get bitten by this when they try to align code for visual purpose :

draw_sprite(bitmap1, 000, more_arguments); // 000 = 0, all good so far
draw_sprite(bitmap1, 005, more_arguments); // 005 = 5, all good so far
draw_sprite(bitmap1, 010, more_arguments); // 010 = 8, uh-oh
draw_sprite(bitmap1, 100, more_arguments); // 100 = 64, uh-oh

Peter Hull
Member #1,136
March 2001

If you didn't know what 0xff meant, how did you title this thread "Hex numbers in C?"
???

torhu
Member #2,727
September 2002
avatar

Audric said:

draw_sprite(bitmap1, 100, more_arguments); // 100 = 64, uh-oh

Looks a lot like one hundred to me :P

Audric
Member #907
January 2001

argh, bad example indeed! sixty-four would be 0100
edit: Actually this illustrates well how you can easily get some lines that behave like you want, some that don't, if nobody notices the octal prefix it can drive you crazy.

Chris Katko
Member #1,881
January 2002
avatar

I've never seen someone do that but I don't doubt it happens...

why wouldn't you just use whitespace to indent numbers?

foo(  1);
foo( 10);
foo(100);

I mean, can you easily read:

0000000000001

over

            1

Anyway?

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

bamccaig
Member #7,536
July 2006
avatar

It depends what the numbers are for. Sometimes the code is just easier to understand in a different base. Typically when you're relying on bit patterns and bitwise operators. Or if the numbers are visually aligned to match the data they represent it could be that you need zeros to fill the holes for the visual to be easy to understand. If it's purely for aesthetics so that lines align better with one another then spaces should be fine though.

Chris Katko
Member #1,881
January 2002
avatar

Y AREN'T YOU PLAYING DUKE?!

Also, IIRC, D doesn't use octals unless you specifically request them with a template converter. Which is nice, so:

assert(00100 == 100);

To get them you'd use
https://dlang.org/library/std/conv/octal.html

// same as 0177
auto x = octal!177;
// octal is a compile-time device
enum y = octal!160;
// Create an unsigned octal
auto z = octal!"1_000_000u";

Obviously, I'm not saying "omg, switch to D" but simply pointing out that this silliness doesn't exist in every language.

The only time I've EVER seen octal used was for UNIX/Linux file access permissions. And even then I just use +w (add write) instead of 1+4+2=7 or whatever nonsense it is. And I've programmed web apps, SQL apps, front-end/back-end, games, and manually programmed registers on a 68xxx Motorala embedded CPU. And to clarify there, I'm not bragging, I'm saying I've seen a large amount of programming niches and I've still never seen them used--or, if they were used, they were treated with extreme care because everyone was afraid of them.

[edit] Okay, I am half-right, they are not supported. However, it will error out to warn you that you have attempted to create a "00100" octal number and you need std.conv.octal instead. So you can't use the "0" indenting method, but it will prevent you from making a C gotcha bug because you have to explicitly request it.

Come to think of it, the same framework (thanks to compile time execution) does allow you to implement all kinds of standard library number conversions (as well as your own custom ones). You could very simply write a Sexagesimal (base60) parser. You could also use compile-time strings to convert something neat like a complex number. Like

auto x = complex!"60+i30"; 

// calls a complex function that takes a string, evaluates at compile-time, into a 
// number. (Though you'd need some complex data type that can hold the two variables)

Though you could just as easily use and forgo a string parser:

auto x = complex(60, 30);

where the first argument is the real component and the second is imaginary. So there's debate over which is easier/better/whatever. Maybe your non-main programmers / part-time programmers who are more scientists than programmers, would prefer the string method.

The point is, there's options.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Doctor Cop
Member #16,833
April 2018
avatar

Thank you all, I thought that 0xff was an address to some memory location cause memory locations are in hexadecimal.

bamccaig
Member #7,536
July 2006
avatar

Memory locations are actually in binary (like all other numbers understood directly by the CPU in our computers).. They're often expressed as hexadecimal because it's easier to convert to and from binary than decimal, and perhaps because it's shorter to express too. In C, typically the only difference between a memory address and an integer is the type of variable storing it. You can actually do arithmetic with addresses, obviously, but you could also treat plain integers as memory addresses (but if those addresses point to memory you aren't allowed to read or write to then your program will be killed).

The reason it is used in your example is the same reason its used for memory addresses in computers: it's easier to convert between hexidecimal and binary than it is to convert between decimal and binary. Ultimately, computer instructions are just manipulating bits in computer memory; manipulating the bits of numbers. To manipulate the memory in interesting ways you need to be able to understand how you're changing the bits.

Audric
Member #907
January 2001

In practice, you will only see hard-coded memory addresses when the source code is for very specific hardware where those addresses are meaningful. For example, MS-DOS games used to write at 0xA000 and above to paint pixels on the screen (The VGA screen buffer starts there), and ARM architecture reserves the address 0x40000000 and above for peripheral I/O.

Doctor Cop
Member #16,833
April 2018
avatar

thanks Audric, i was thinking about why so many GUI libraries used these hex numbers.

Audric
Member #907
January 2001

They're a bit of a visual help to check what you're doing in a bit field.

#define DEPRECATED_FLAGS 0x0000000F
#define TYPE_FLAGS       0x000007F0
#define IMPORTANT_FLAG   0x00000800
#define COLLISION_FLAGS  0x00FFF000
// unused so far :       0xFF000000

Chris Katko
Member #1,881
January 2002
avatar

Basically, they're more compact than binary, but because 16 is divisible by 2 (2*2*2*2) the numbers line up well.

        F is 4 bits.
       FF 8-bits.
     FFFF 16-bits
FFFF FFFF 32-bits

So you want to set one 8-bit value inside a 32-bit number? It's either:

FFFF FFFF 

xxFF FFFF 
^^ here

FFxx FFFF 
  ^^ here

FFFF xxFF 
     ^^ here 

FFFF FFxx 
       ^^ or here

If we were talking about a 32-bit number that would be:

00000000000000000000000000000000
Yick.

A 64 bit number?

0000000000000000000000000000000000000000000000000000000000000000

vs

FFFF FFFF FFFF FFFF

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

ZoriaRPG
Member #16,714
July 2017
avatar

bamccaig said:

Memory locations are actually in binary (like all other numbers understood directly by the CPU in our computers).. They're often expressed as hexadecimal because it's easier to convert to and from binary than decimal, and perhaps because it's shorter to express too. In C, typically the only difference between a memory address and an integer is the type of variable storing it. You can actually do arithmetic with addresses, obviously, but you could also treat plain integers as memory addresses (but if those addresses point to memory you aren't allowed to read or write to then your program will be killed).
The reason it is used in your example is the same reason its used for memory addresses in computers: it's easier to convert between hexidecimal and binary than it is to convert between decimal and binary. Ultimately, computer instructions are just manipulating bits in computer memory; manipulating the bits of numbers. To manipulate the memory in interesting ways you need to be able to understand how you're changing the bits.

Note that C does not have an in-built method of expressing binary values. That's more often why hex values are used.

Chris Katko
Member #1,881
January 2002
avatar

I keep forgetting that!

When I used C and binary values, it was with "Motorala C" an IDE/compiler suite for the 68xxx dev boards and they added binary (ala 0b10101111) as an option because of how often you set register flags.

GNU C also has this extension:

https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html#Binary-constants

They also have other nifty extensions like nested functions! (If you don't mind being tied to a specific compiler. But nowadays it's GNU, Clang, and rarely Intel/Microsoft. So it's not like you're tried to "Borland Turbo C" and if they stop making it you're screwed.)

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

torhu
Member #2,727
September 2002
avatar

C++14 has got binary literals.

ZoriaRPG
Member #16,714
July 2017
avatar

I keep forgetting that!

When I used C and binary values, it was with "Motorala C" an IDE/compiler suite for the 68xxx dev boards and they added binary (ala 0b10101111) as an option because of how often you set register flags.

GNU C also has this extension:

https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html#Binary-constants

They also have other nifty extensions [gcc.gnu.org] like nested functions! (If you don't mind being tied to a specific compiler. But nowadays it's GNU, Clang, and rarely Intel/Microsoft. So it's not like you're tried to "Borland Turbo C" and if they stop making it you're screwed.)

-----sig:

Yes, Motorola were always clever about supporting their own architecture.

Again though, I'm talking about C99, without extra stuff tacked on. Remember that those are special extensions, and not part of the actual C spec!

(That means that your code may or may not be portable.)

torhu said:

C++14 has got binary literals.

Nice to see that they've finally caught up with 1987 in the cpp spec. :D

If only the rest of the stuff that they constantly tack onto cpp to make it more like Java were as useful. (I'll admit that one useful thing, in the newer spec, is variable sized arrays. I'm not sure if that made it fully into C++14, though. Some C++03 compilers support it, but again, code portability takes a nosedive if you try to use them.)

In general, I try to make things that work for the lowest common denominator. My output would compile equally well on an Atari Falcon, as on a modern system.

Chris Katko
Member #1,881
January 2002
avatar

ZoriaRPG said:

my output would compile equally well on an Atari Falcon, as on a modern system.

That's not actually a positive. You've missed the point of portability.

No matter what program you write, it is NOT designed to run on every machine ever. It's not designed for mainframes. It's not designed for routers. It's not designed for gameboys or Apple watches. It won't run on a "LISP Machine." It won't run on an NES.

You're always supposed to reduce your program's scope to a "Reasonable subset" of the set of all machines possible. And then, use optimizations that apply to that subset.

You're basically throwing away decades of advancements. No SSE. No MMX (!). 64-bit architectures! Needlessly.

Hell, why even use floating-point numbers? Those only work in hardware if you have a floating-point coprocessor! Did you compile in the necessary software floating point emulation library?

Do you support ASCII terminals, because videocards don't exist everywhere?

Why ever use C++ when C is on more systems? Why use C99 when C89 is supported on more systems?

The point is, you're already doing what I'm talking about. You just didn't realize it. The goal is never "maximum portability." The goal is "maximum utility for my desired subset of all machines". You should spend time deciding the subset (my target audience of machines), and then you should use any and all optimizations (and ease of programming) advancements available for that subset.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

ZoriaRPG
Member #16,714
July 2017
avatar

That's not actually a positive. You've missed the point of portability.

No matter what program you write, it is NOT designed to run on every machine ever. It's not designed for mainframes. It's not designed for routers. It's not designed for gameboys or Apple watches. It won't run on a "LISP Machine." It won't run on an NES.

Yes, and no. I prefer to work within a compiler spec that I know. I also don't want to make stuff that demands the absolute latest compilers. My point, is that when you start using stuff that's only supported by some compilers, then your codebase can easily break based on the system architecture, and the compiler used to build it--on MODERN systems!

I'd use binary literals in something personal, but no if I was making an open source project of it. I absolutely hate when stuff wants you to use a very specific compiler, and a specific version or higher thereof; and I deal with that regularly.

That's also an issue with C/C++ in general, though. In theory, any older code should process and compile via a compiler flag based on the implementation version, but that's just nopt how the real world works.

Quote:

You're basically throwing away decades of advancements. No SSE. No MMX (!). 64-bit architectures! Needlessly.

Stuff such as MMX should be handled by the compiler as optimisation in the ASM. It's specifically architecturally locked. Do you think that custom MMX optimisation means two pins on Power architecture? or Arm? or PPC?

So, no, I don't write specifically for MMX. I'm also not originally an i386 bloke, much less an i686 bloke. My background is in 6809, 6800, 65xx, 68K, and PPC. I worked with some i286 stuff, years ago.

As for SSE, I don't make anything that requires it. I'm neither in the business of making stuff that does made amountsw of calculations, nor in the business of 3D.

If I were to need those facilities, I'd use them.

Quote:

Hell, why even use floating-point numbers? Those only work in hardware if you have a floating-point coprocessor! Did you compile in the necessary software floating point emulation library?

Tpically, I don't use any floating point types unless they are mandatory. That's very likely based on my ge, and my background, but I only occasionally have an absolute need for floating point types.

Again, if I was making something for superscalar maths, then sure, I'd use them. I'd also use Power7 and not care about portability, as what I'd be making is so specific, that it is effectively the software equivalent of an ASIC.

My ultimate point, is while these extensions do exist, that people who are new to the entire idea should do things the way that is the most widely supported. I don't know why binary literals weren't in C89, C99, C++03 or what-have-you, but remember, even bool wasn't in the C spec!

...and there's a good lesson, because use of bool (or _Bool in C99) is often misunderstood, and overused these days. I see people doing this, thinking that it lowers their software footprint, versus char. ???

I'll add, as an anecdote, that it's possible to write C code that runs the same on a modern PC, a C64, an Apple II, and a NES. Have a look at CC65, and some of the C compilers for the Apple II and the C64. There are still ways to compile that code to run on w32 and Linux; if that's part of your goal. ;)

Audric
Member #907
January 2001

ZoriaRPG, I can see where you're coming from, but I also understand that if everybody waits for a new compiler functionality to be in baseline standard before they use them, nobody tests / promotes it, and then there's no chance that it gets adopted by other compilers, no incentive to put it in a standard.

bamccaig
Member #7,536
July 2006
avatar

A more productive thing to do is push vendors or contribute to open source projects to get new features supported. Update the old so that it works with the new. It's pretty rare that you'll be writing modern day software with no intention of having it supported on outdated/obsolete platforms, and still having it compatible with those platforms. If you want it to be available for obscure platforms, release the source code, and let enthusiasts develop their own platform-specific patches to transform it back into compliance with the old. It's better to take advantage of new features to help make your code easier to get right, and easier to understand, and therefore fewer bugs.

 1   2 


Go to: