Printb

Lab 0x1

Review 

Goal: Think about C variables as bits

Review: Newish:
- for - bits
- C types - bytes
- booleans - operators
  • In addition to large amounts of contextual and background material, there are three main exercises for this lab:
    • Script
    • Printb
    • it/ool

Podman 

Setup

  • For this lab, I used the following Containerfile
    • Same as lecture but I added python3
Containerfile
  • I built via the following:
  • I conducted the full lab within a single container’s vim instance.
  • I conducted all work within this vim window and it’s :term

PyBool 

==

  • To begin, we recall Enigma:
    • Unlike Python booleans, C has no boolean type.
      • Rather it has truthiness, akin to Python if statements with numerical conditions.
      • The numerical value zero is false.
      • All other numerical values are true.
  • The simplest way for me to understand bools is via equality testing
    • First, Python

Verify install

  • Before anything else, I verify I have an install of Python3.
python3 --version
  • I found I had 3.12.3 - not great, not terrible.

Python -c

  • We can evaluate a single Python expression - a single line of code - via -c
python3 -c "print(1 == 1)"
  • As expected, this prints True - capital “T”, lowercase “rue”.
    • We’ve seen this before.

Format print

  • However, this isn’t exactly true-to-form
  • Python print is not a format print by default.
  • For equivalence, we must use a format print.
  • We can naively use a format without specifying a type…
python3 -c 'print(f"{1==1}")' 
  • This still gives True, but also has no C equivalent!
    • We have to provide some letter to determine how a value is printed

2 %b | ! 2 %b

Java

  • There is a language called Java, technically.
    • <loud grumbling>
  • It has a format print, and uses %b for booleans, I hear.
  • You can test if you want:
    • Yoink a Java container.
    podman run -it openjdk
    • It will drop you into something called jshell
    • We can do a quick Java printf
    System.out.printf("1 == 1 is %b\n",1 == 1);
    • I got this output, which I don’t understand at all
    1 == 1 is true
    $1 ==> java.io.PrintStream@34c45dca
    • It does say “true” though, that’s fun!
    • Apparently you can use the following to leave jshell
    /ex
    • I cleaned the Java off my system with
    podman system prune
    • I made sure it was gone with
    podman images

Pythonic b

  • After that digression, let’s try b in Python
python3 -c 'print(f"{(1==1):b}")' 
  • It prints, of all things:
1
  • Well, that’s interesting.
    • If you want some fun first
    python3 -c 'print(f"{2:b} or not {2:b}")'

Script 

Scripted Testing of Programming/Computing

Or, “Computer Science”

C truthiness

  • Python is written in C and correspondingly lacks a way to print something as a boolean.
    • Unlike C, Python has a boolean class, but C has no classes, and…
    • Therefore C has no booleans (or strings or etc.)
  • C has a somewhat complicated relationship with booleans we will explore, but
    • In the meantime, stick to ==
  • To decide how to printf and ==, we consult the C89 specification:

d Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtol function with the value 10 for the base argument. The corresponding argument shall be a pointer to integer.

i Matches an optionally signed integer, whose format is the same as expected for the subject sequence of the strtol function with the value 0 for the base argument. The corresponding argument shall be a pointer to integer.

o Matches an optionally signed octal integer, whose format is the same as expected for the subject sequence of the strtoul function with the value 8 for the base argument. The corresponding argument shall be a pointer to unsigned integer.

u Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtoul function with the value 10 for the base argument. The corresponding argument shall be a pointer to unsigned integer.

x Matches an optionally signed hexadecimal integer, whose format is the same as expected for the subject sequence of the strtoul function with the value 16 for the base argument. The corresponding argument shall be a pointer to unsigned integer.

e,f,g Matches an optionally signed floating-point number, whose format is the same as expected for the subject string of the strtod function. The corresponding argument shall be a pointer to floating.

s Matches a sequence of non-white-space characters. The corresponding argument shall be a pointer to the initial character of an array large enough to accept the sequence and a terminating null character, which will be added automatically.

[ Matches a nonempty sequence of characters from a set of expected characters (the scanset ). The corresponding argument shall be a pointer to the initial character of an array large enough to accept the sequence and a terminating null character, which will be added automatically. The conversion specifier includes all subsequent characters in the format string, up to and including the matching right bracket ( ] ). The characters between the brackets (the scanlist ) comprise the scanset, unless the character after the left bracket is a circumflex ( ^ ), in which case the scanset contains all characters that do not appear in the scanlist between the circumflex and the right bracket. As a special case, if the conversion specifier begins with [] or [^] , the right bracket character is in the scanlist and the next right bracket character is the matching right bracket that ends the specification. If a - character is in the scanlist and is not the first, nor the second where the first character is a ^ , nor the last character, the behavior is implementation-defined.

c Matches a sequence of characters of the number specified by the field width (1 if no field width is present in the directive). The corresponding argument shall be a pointer to the initial character of an array large enough to accept the sequence. No null character is added.

p Matches an implementation-defined set of sequences, which should be the same as the set of sequences that may be produced by the %p conversion of the fprintf function. The corresponding argument shall be a pointer to a pointer to void . The interpretation of the input item is implementation-defined; however, for any input item other than a value converted earlier during the same program execution, the behavior of the %p conversion is undefined.

n No input is consumed. The corresponding argument shall be a pointer to integer into which is to be written the number of characters read from the input stream so far by this call to the fscanf function. Execution of a %n directive does not increment the assignment count returned at the completion of execution of the fscanf function.
  • In brief
% suffix Meaning
d decimal (base 10)
i integer
o octal (base 8)
u unsigned (positive)
x hexadecimal (base 16)
e,f,g float
s string
c character (ascii/utf-8)
p pointer (more latter)
n nothing
% literal %
  • Many of these are meant for scanning, not printing, so they are weird (i, n)
  • Even briefer:
codes = ['d','i','o','u','x','e','f','g','s','c','p','n']
  • Wait a minute. I know how to:
    • Write a loop in Python
    • Make a string in Python
    • Write a string to a file in Python
    • Run commands in Python
      • Including podman commands
  • I know how to:

Major Exercise: Script

  • Write a script t test all format codes in C89 to print 1 == 1 and think about the results.
  • Spoiler alert: I did not see anything that said “True”.

Binary 

ObX

  • Python classes obscure the internal data represention of the device.
  • The C program language clarifies the representation so we can work with it more directly.
  • One detail revealed is binary versus booleans
    • The binary number 0b0 is regarded as the PyBoolean value False
    • The binary number 0b1 is regarded as the PyBoolean value True
    • The next binary number is 0b01, how to think of this?
      • That could be a numerical value
        • Which would be the truthy value True, or
      • That could be an array of booleans
        • 0b01[0] == False and 0b01[1] == True, perhaps
  • Treating numerical values as boolean arrays is a core insight of (some) cryptographic algorithms.
    • It touches on the broader learning goal of “pointers”
    • This is partially revealed in Python, versus Java, with the b format code
python3 -c "[print(f'{i:04b}') for i in range(10)]"

A %b C format code

  • The C programming recently gained a %b format code
    • It lacked one until C23 - just last year
    • C23 is not widely adopted…
      • The C language toolchain is a massive software endeavour
      • Changes to the ecosystem can take decades
      • Think: How often does a new operating system code out.
        • Not like, Windows 11… like Windows
    • Some compilers, like gcc, kinda support %b usage
      • I just ran some code in a few, and it sort worked.
      • Here is an odd feature of C:
        • Just because it isn’t C, doesn’t mean gcc can’t handle it
        • These are usually called “gnu extensions” or “non-standard features”
  • You can use %b in whatever version of gcc I had in my container…
    • Try both of these:
    gcc printb.c
    gcc printb.c -pedantic

Minor Exercise

  • Using %b, write a C program that compiles to an executable which, when run, produces the following output:
  • It may be helpful to work with Python first.

Printb 

Major Exercise: Printb

This code base will see use on the new homework, Macros

  • It is a fairly simply matter to produce a pedantic-compliant printb function, which prints a numerical value in binary with:
    • C math,
    • printf statements, and
    • for loops.
      • Or perhaps while loops
  • Do so. For now, target the char type, or another type of your choice.

Extensions

  • Advanced students may wish to consider:
    • While loops
    • Bit shift operators like >>
    • Bitwise operators like &
    • The atoi function for testing
    • Standarizing a left pad via any number of methods
    • Macros, to be char-nonspecific

Reference implementation

  • The reference implementation, which is not pedantic-compliant, is
printb_not_quite.c
#include <stdio.h>

int printb(char n) {
        printf("%b", n);
        return 0;
}

it/ool 

“B” + .. ? “it” : “ool”

This title is combination of Pythonic and C, don’t look at it too closely.

  • Python:
    • Has bools
    • Doesn’t have bits, or binary, really
      • But also not not really, binary is everywhere
    • But decimal is clear the expected representation in Python.
  • C
    • Is unopinionated on bases between 8, 10, 16
    • Has strong unofficial support for binary
    • Has no booleans.
  • This unsurprising leads to differences in boolean algebra.
    • My take: C values a boolean arrays
  • Here are some C operators, with number of arguments.
    • There are 10, but most of this lab is about the first 8
Operator Arity Example
& 2 x & y
| 2 x | y
^ 2 x ^ y
~ 1 ~y
&& 2 x && y
|| 2 x || y
!= 2 x != y
! 1 !y
>> 2 x >> y
<< 2 x << y

Major Exercise: it/ool

These results will see use on the new homework, Macros

  • Determine the logical, or other, operation to which each operator corresponds, and
  • Determine whether it is acting on bits-as-booleans or bits-as-boolean-arrays