0

I am trying to define 4-bit, 20-bit, 24-bit and 36-bit unsigned integers in C in simplest way.

  • No bitfiels
  • Portability is not an issue
  • Memory space is not an issue either
  • C99 and later is fine
  • 3
    Unless you happen to have a 4 bit MCU or some such, you can't. Not without creating lots of abstraction layers at least. What is the actual problem you are trying to solve with this? – Lundin Mar 23 '22 at 10:35
  • Do you mean I can't have uint4_t or all of them? – Starcrescent Mar 23 '22 at 10:38
  • 2
    @Starcrescent You can't have any of them because storing a 4 bit variable on a 8 bit CPU means allocating a `uint8_t`. Again, what is the problem you are trying to solve? Or is there no problem to solve and you are merely looking to create one? – Lundin Mar 23 '22 at 10:41
  • 3
    [``](http://port70.net/~nsz/c/c11/n1570.html#7.20.1.2) defines `uint_least8_t`, `uint_least16_t`, `uint_least32_t`, and `uint_least64_t`. Use this and clip computations `mod 2^N`. – pmg Mar 23 '22 at 10:46
  • @Lundin. I have CPU emulation problem that I have to compare some certain performance for 4/8/16/32/64-bit CPUs with 8/16/20/24/32/36/48/64-bit address space. I need them for address counters. CPUs are hypothetical meaning they have not been designed yet! – Starcrescent Mar 23 '22 at 10:50
  • 1
    Well... you simply can't compare performance of hypothetical CPUs, because there's a whole lot more than data width and address bus width to consider. Instruction sets, memory access, alignment, branch prediction, pipelining and so on and so on... – Lundin Mar 23 '22 at 10:57
  • @Lundin I do not want to go into CPU design argument. There are some preliminary decisions have to be made. However, fixed with 4/20/24-bit unsigned integer problem remains. – Starcrescent Mar 23 '22 at 11:00
  • 1
    But there is no such problem, since using some `uint4_t` on your x86_64 PC simulator will simply not be the slightest helpful for determining how fast you fictional 4 bit CPU is. – Lundin Mar 23 '22 at 11:02
  • Anyway, I'm going to close vote as unclear now because this is a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) if I ever saw one. – Lundin Mar 23 '22 at 11:09
  • if memory isn't an issue then there's absolutely no reason to create such types. You have to reduce modulo the result after each operation yourself, and the result is much slower which makes comparing performance useless. [Which C datatype can represent a 40-bit binary number?](https://stackoverflow.com/q/9595225/995714), [If a 32-bit integer overflows, can we use a 40-bit structure instead of a 64-bit long one?](https://stackoverflow.com/q/27705409/995714) – phuclv Mar 23 '22 at 11:10
  • For the smaller lengths, code could use a _bitfield_ `struct { unsigned x:4; } my_uint4_t;` to get close to OP's goal. Ah, I see OP had "No bitfiels". Missed that when searching for "bitfield". – chux - Reinstate Monica Mar 23 '22 at 13:05
  • FWIW, I have used `uint24_t` on 16-bit processors. So if you do create some 4-bit, 20-bit, 24-bit and 36-bit type, avoid using names that may someday later appear and conflict. – chux - Reinstate Monica Mar 23 '22 at 13:11

1 Answers1

1

Assuming what you said in comments below your question, you're facing several problems:

  1. Usual way to do that in CPU emulation is to use the shortest type that can contain what you want to store. So, for an uint4_t, you'll need a uint8_t and a uint20_t will need a uint32_t. Then, in case of underflow/overflow, you'll set your emulated CPU flags accordingly.
  2. Doing this in pure C is just hell. Prefer C++, at least to define types and operators properly and don't get a headache by calling an infamous number of functions (with potential PEBKAC errors) on each use of these types. CPU emulation in C is done because most CPU shares the same register sizes, and it allows a bit more of speed.
  3. If you want to compare your virtual CPU performances, you'll need to count not the real time that your program used, but the VIRTUAL time your emulated CPU used. In clock cycles. So you'll need to include, with each emulated instruction, its execution time (clock cycles, memory wait states, pipeline flushing, etc.).
  4. The only other way will be to split your emulated types to arrays of bool (8 bits). So, your uint4_t will become, internally, a char[4], so you'll be able to either access individual bits AND to manipulate it as a single element. But for uint36_t, it will starts to be quite "fun" to use and you'll face some other problems on your host machine, like cache being invalidated too often and alignment problems. And you'll need to write all basic operations for these types, anyway, you won't be able to rely on C ones (unlike what is possible when using the shortest type above, see first point).

CPU emulation is not the easiest thing to do, and trying to compare performances of an emulated CPU to another emulated CPU is usually totally irrelevant. It's somewhat possible because you try to compare variants of the same CPU, but you'll need a talented hardware engineer to give you all execution times for all emulated instructions before trying to do anything else.

Wisblade
  • 1,483
  • 4
  • 13