Skip to content

Instantly share code, notes, and snippets.

@timyates
Last active August 17, 2021 20:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timyates/e051d5752231b8a2434d68dfa84fce61 to your computer and use it in GitHub Desktop.
Save timyates/e051d5752231b8a2434d68dfa84fce61 to your computer and use it in GitHub Desktop.
Overlay a struct over a block of memory in C
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char UCHAR;
typedef struct rgba
{
UCHAR r;
UCHAR g;
UCHAR b;
UCHAR a;
} RGBA;
void printRgba(RGBA rgba) {
printf("[%d, %d, %d, %d]\n", rgba.r, rgba.g, rgba.b, rgba.a);
}
int main(int argc, char const *argv[])
{
// Space for 100 elements
int *block = malloc(100 * sizeof(RGBA));
void *offset = (void*) block;
// Overlay our struct over the array, and set some values
((RGBA*)offset)->r = 1;
((RGBA*)offset)->g = 2;
((RGBA*)offset)->b = 3;
((RGBA*)offset)->a = 4;
// prints [1, 2, 3, 4]
printRgba(*(RGBA*)offset);
// Move it forward 1 UCHAR
offset += sizeof(UCHAR);
// prints [2, 3, 4, 0]
printRgba(*(RGBA*)offset);
free(block);
}
// And similar in Panama (Azul java 16.0.2 with --add-modules jdk.incubator.foreign)
package com.bloidonia;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemoryLayouts;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.SequenceLayout;
import java.lang.invoke.VarHandle;
public class Main {
public static void main(String[] args) {
GroupLayout rgba = MemoryLayout.ofStruct(
MemoryLayouts.JAVA_BYTE.withName("r"),
MemoryLayouts.JAVA_BYTE.withName("g"),
MemoryLayouts.JAVA_BYTE.withName("b"),
MemoryLayouts.JAVA_BYTE.withName("a")
);
SequenceLayout seqStruct = MemoryLayout.ofSequence(100, rgba);
VarHandle VHr = seqStruct.varHandle(byte.class, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("r"));
VarHandle VHg = seqStruct.varHandle(byte.class, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("g"));
VarHandle VHb = seqStruct.varHandle(byte.class, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("b"));
VarHandle VHa = seqStruct.varHandle(byte.class, MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("a"));
try(MemorySegment buffer = MemorySegment.allocateNative(seqStruct)) {
VHr.set(buffer, 0, (byte)1);
VHg.set(buffer, 0, (byte)2);
VHb.set(buffer, 0, (byte)3);
VHa.set(buffer, 0, (byte)4);
MemorySegment memorySegment = buffer.asSlice(1);
// prints [2, 3, 4, 0] 😎
System.out.printf("[%d, %d, %d, %d]", (byte)VHr.get(memorySegment, 0), (byte)VHg.get(memorySegment, 0), (byte)VHb.get(memorySegment, 0), (byte)VHa.get(memorySegment, 0));
}
}
}
@timyates
Copy link
Author

My interest got piqued by this excellent series of posts from Carl Dea on Project Panama.

Back in the day, I used to love doing this sort of thing, allocating a contiguous block of memory, and then accessing it by overlaying different structs to provide context and shape to the chunks.

Panama is being actively developed, so the Java I used above (Azul Java 16.0.2 with the preview features turned on) is probably already hopelessly out of date

But fun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment