Skip to content

Instantly share code, notes, and snippets.

@imaami
Created March 16, 2026 22:34
Show Gist options
  • Select an option

  • Save imaami/79fda3bc4011ebf039487254d5174050 to your computer and use it in GitHub Desktop.

Select an option

Save imaami/79fda3bc4011ebf039487254d5174050 to your computer and use it in GitHub Desktop.
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "example_obj.h"
struct obj
obj (char const *name)
{
struct obj ret = {0};
if (!name) {
ret.error = EFAULT;
return ret;
}
int e = snprintf(ret.name.arr, sizeof ret.name.arr, "%s", name);
if (e < 0) {
ret.error = errno;
return ret;
}
if (e >= (int)sizeof ret.name.arr) {
/* Name truncated, allocate memory */
char *name_ptr = strdup(name);
if (!name_ptr) {
ret.error = errno;
return ret;
}
ret.name.ptr = name_ptr;
ret.flags |= OBJ_NAME_ALLOC;
}
return ret;
}
int
obj_init (struct obj *dest,
char const *name)
{
if (!dest)
return EFAULT;
*dest = obj(name);
return dest->error;
}
void
obj_fini (struct obj *dest)
{
if (dest) {
if (dest->flags & OBJ_NAME_ALLOC)
free(dest->name.ptr);
*dest = (struct obj){0};
}
}
struct obj *
obj_create (char const *name)
{
struct obj *ret = malloc(sizeof *ret);
if (ret)
*ret = obj(name);
return ret;
}
void
obj_destroy (struct obj **p_dest)
{
if (p_dest && *p_dest) {
struct obj *ptr = *p_dest;
*p_dest = nullptr;
obj_fini(ptr);
free(ptr);
}
}
static inline char const *
obj_get_name_ (struct obj const *src)
{
return (src->flags & OBJ_NAME_ALLOC)
? src->name.ptr : src->name.arr;
}
char const *
obj_get_name (struct obj const *src)
{
return src ? obj_get_name_(src) : nullptr;
}
int
obj_get_error (struct obj const *src)
{
return src ? src->error : -1;
}
void
obj_print_error (struct obj const *src)
{
if (src && src->error) {
char const *msg = strerror(src->error);
char const *name = obj_get_name_(src);
if (name && *name)
fprintf(stderr, "%s: %s\n", name, msg);
else
fprintf(stderr, "%s\n", msg);
}
}
#ifndef EXAMPLE_OBJ_H_
#define EXAMPLE_OBJ_H_
enum obj_flags {
OBJ_NAME_ALLOC = 1
};
/* Example object with a name string. */
struct obj {
union {
char arr[sizeof (char *)];
char *ptr;
} name;
unsigned flags;
int error;
};
/* Initializes and returns a new object by-value.
* May allocate memory for members if necessary.
*/
extern struct obj
obj (char const *name);
/* Initializes, but does not allocate, an object.
* May allocate memory for members. Returns 0 on
* success and an error number on failure.
*/
extern int
obj_init (struct obj *dest,
char const *name);
/* Frees allocated member data, if any, but not
* the object itself.
*/
extern void
obj_fini (struct obj *dest);
/* Allocates and initializes a new object.
* returns a pointer to created object.
*/
extern struct obj *
obj_create (char const *name);
/* Uninitializes and frees the object, then
* sets caller's object pointer to nullptr.
*/
extern void
obj_destroy (struct obj **p_dest);
/* Returns pointer to name or nullptr. */
extern char const *
obj_get_name (struct obj const *src);
/* Returns the error number, if any. */
extern int
obj_get_error (struct obj const *src);
/* Prints error description or nullptr. */
extern void
obj_print_error (struct obj const *src);
#endif /* EXAMPLE_OBJ_H_ */
#include <stdio.h>
#include "example_obj.h"
int
main (int c,
char **v)
{
struct obj program = obj(v[0]);
fputs(obj_get_name(&program), stdout);
for (int i = 0; ++i < c;) {
struct obj *arg = obj_create(v[i]);
if (!arg)
continue;
char const *name = obj_get_name(arg);
if (name)
printf(" %s", name);
obj_destroy(&arg);
}
putchar('\n');
obj_fini(&program);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment