There are many ways to turn a value into a string in this stack. This doc catalogues every one () so you can pick the right tool without guessing.
TLDR — The "I just want sprintf / stringWithFormat:" Cheat Sheet #
These are the six format-string entry points you'll use most often, sorted by memory-management style:
| You want… | Use this | Output type | Free it? | Example |
|---|---|---|---|---|
| Stack (short-lived) | mulle_sprintf_do(s, fmt, …) |
char * |
no | mulle_sprintf_do(s, "%d", i) { use(s); } |
| Build incrementally (C) | mulle_buffer_do(buf) { mulle_buffer_sprintf(...); } |
mulle_buffer * |
no (auto) | mulle_buffer_do(buf) { mulle_buffer_sprintf(buf, "%d", i); … extract_string; } |
| Build incrementally → autoreleased C string | mulle_buffer_do_autoreleased_string(buf, NULL, s) { … } |
char * |
no (pool) | mulle_buffer_do_autoreleased_string(buf, NULL, s) { mulle_buffer_sprintf(buf, "%d", i); } |
| Heap (must free) | mulle_asprintf(&p, fmt, …) |
char * |
mulle_free(p) |
mulle_asprintf(&p, "%d", i); … mulle_free(p); |
| Autoreleased C string (one-shot) | MulleObjC_asprintf(fmt, …) |
char * |
no (pool) | s = MulleObjC_asprintf("%d", i); |
| Autoreleased NSString | [NSString stringWithFormat:…] |
NSString * |
no (pool) | s = [NSString stringWithFormat:@"%d", i]; |
| Mutable NSString | [NSMutableString string] + -appendFormat: |
NSMutableString * |
no (pool) | ms = [NSMutableString string]; [ms appendFormat:@"%d", i]; |
Prefer mulle_buffer_do / mulle_buffer_do_autoreleased_string over
mulle_snprintf — they grow as needed, compose naturally, and avoid fixed buffer management bugs.
Reference Table #
| API / Macro | Level | Output Type | Lifetime / Ownership | NUL-terminated? | Format args? | Allocator | Notes |
|---|---|---|---|---|---|---|---|
mulle_snprintf(buf, size, fmt, ...) |
C | char * (caller buf) |
caller owns storage | yes | yes | — | returns -1 on overflow, always NULs |
mulle_sprintf(buf, fmt, ...) |
C | char * (caller buf) |
caller owns storage | yes | yes | — | unsafe — no size limit |
mulle_vsnprintf(buf, size, fmt, va) |
C | char * (caller buf) |
caller owns storage | yes | yes (va_list) | — | va_list variant |
mulle_mvsnprintf(buf, size, fmt, va) |
C | char * (caller buf) |
caller owns storage | yes | yes (mulle_vararg) | — | mulle_vararg variant |
mulle_asprintf(&strp, fmt, ...) |
C | char * (heap) |
caller must mulle_free() |
yes | yes | mulle_default_allocator |
heap string, use with mulle_malloc family |
mulle_vasprintf(&strp, fmt, va) |
C | char * (heap) |
caller must mulle_free() |
yes | yes (va_list) | mulle_default_allocator |
va_list variant |
mulle_mvasprintf(&strp, fmt, va) |
C | char * (heap) |
caller must mulle_free() |
yes | yes (mulle_vararg) | mulle_default_allocator |
mulle_vararg variant |
mulle_allocator_asprintf(a, &p, fmt, ...) |
C | char * (heap) |
caller must free via a |
yes | yes | custom | supply your own allocator |
mulle_allocator_vasprintf(a, &p, fmt, va) |
C | char * (heap) |
caller must free via a |
yes | yes (va_list) | custom | supply your own allocator |
mulle_sprintf_do(s, fmt, ...) { … } |
C | char * (stack buffer) |
valid only inside {…} block |
yes | yes | — | stack-local; auto-cleanup on block exit |
mulle_vsprintf_do(s, fmt, args) { … } |
C | char * (stack buffer) |
valid only inside {…} block |
yes | yes (va_list) | — | va_list variant of above |
mulle_buffer_sprintf(buf, fmt, ...) |
C | appends to mulle_buffer |
buffer owns | no | yes | buffer's allocator | does not NUL-terminate; call mulle_buffer_make_string() if needed |
mulle_buffer_vsprintf(buf, fmt, va) |
C | appends to mulle_buffer |
buffer owns | no | yes (va_list) | buffer's allocator | va_list variant |
mulle_buffer_mvsprintf(buf, fmt, va) |
C | appends to mulle_buffer |
buffer owns | no | yes (mulle_vararg) | buffer's allocator | mulle_vararg variant |
mulle_buffer_do(name) { … } |
C | mulle_buffer * (stack) |
auto-cleanup on block exit | no | — | NULL (default) |
idiomatic short-lived buffer |
mulle_buffer_do_flexible(name, capacity) { … } |
C | mulle_buffer * (stack) |
auto-cleanup on block exit | no | — | NULL (default) |
with custom starting capacity |
mulle_buffer_add_string(buf, s) |
C | appends to mulle_buffer |
buffer owns | no | — | buffer's allocator | raw string append |
mulle_buffer_add_bytes(buf, bytes, len) |
C | appends to mulle_buffer |
buffer owns | no | — | buffer's allocator | raw binary append |
mulle_buffer_extract_string(buf) |
C | char * (heap) |
caller owns, must free | yes | — | buffer's allocator | steals ownership from buffer |
mulle_buffer_extract_bytes(buf) |
C | void * (heap) |
caller owns, must free | no | — | buffer's allocator | steals ownership from buffer |
mulle_printf(fmt, ...) |
C | stdout (stream) |
— | yes | yes | — | output to stdout |
mulle_fprintf(fp, fmt, ...) |
C | FILE * (stream) |
— | yes | yes | — | output to any FILE stream |
mulle_dtostr(value, buf) |
C | char * (caller buf) |
caller owns storage | yes | — | — | double→string; buffer must be ≥25 bytes |
mulle_dtostr_decompose(value) |
C | struct mulle_dtostr_decimal |
value type | — | — | — | decompose double, custom format |
mulle_utf8_convert_to_utf16_string(src, len, a) |
C | mulle_utf16_t * (heap) |
caller must free via a |
yes | — | custom | encoding conversion |
mulle_utf8_convert_to_utf32_string(src, len, a) |
C | mulle_utf32_t * (heap) |
caller must free via a |
yes | — | custom | encoding conversion |
MulleObjC_asprintf(fmt, ...) |
ObjC | char * (heap) |
autoreleased — do not free | yes | yes | mulle_default_allocator |
wrapped in autorelease pool |
MulleObjC_vasprintf(fmt, args) |
ObjC | char * (heap) |
autoreleased — do not free | yes | yes (va_list) | mulle_default_allocator |
va_list variant |
MulleObjC_mvasprintf(fmt, args) |
ObjC | char * (heap) |
autoreleased — do not free | yes | yes (mulle_vararg) | mulle_default_allocator |
mulle_vararg variant |
MulleObjC_strdup(s) |
ObjC | char * (heap) |
autoreleased — do not free | yes | — | mulle_default_allocator |
autoreleased copy of C string |
mulle_buffer_do_autoreleased_string(buf, a, s) { … } |
ObjC | char * (heap) |
autoreleased — do not free | yes | — | custom or NULL | build in buffer → autorelease result |
MulleObjCAutoreleaseAllocation(p, a) |
ObjC | void * |
autoreleased — do not free | — | — | custom or NULL | wrap any malloc'd pointer in autorelease |
-[NSObject UTF8String] |
ObjC | char * (heap) |
autoreleased — do not free | yes | — | — | equivalent to [[self description] UTF8String] |
-[NSObject description] |
ObjC | NSString * |
autoreleased | — | — | — | override to customize |
TypeUTF8String(value) (e.g. CGRectUTF8String, CGSizeUTF8String, …) |
ObjC | char * (heap) |
autoreleased — do not free | yes | — | — | type-specific formatting, returns autoreleased C string |
[NSString stringWithUTF8String:cstr] |
Foundation | NSString * |
autoreleased | — | — | — | create NSString from C string |
[NSString stringWithCString:cstr encoding:e] |
Foundation | NSString * |
autoreleased | — | — | — | NSString from C string with explicit encoding |
[NSString stringWithFormat:fmt, ...] |
Foundation | NSString * |
autoreleased | — | yes | — | formatted NSString |
-[NSString UTF8String] |
Foundation | char * |
valid for lifetime of NSString | yes | — | — | get C string from NSString (not autoreleased!) |
NSMutableString + -appendFormat:fmt, ... |
Foundation | NSMutableString * |
caller retains | — | yes | — | incrementally build NSString; stringWithFormat: but mutable |
NSMutableString + -appendString:s |
Foundation | NSMutableString * |
caller retains | — | — | — | raw NSString append |
NSMutableString + -setString:s |
Foundation | NSMutableString * |
caller retains | — | — | — | replace content |
NSStringFromClass(cls) |
Foundation | NSString * |
autoreleased | — | — | — | class name as string |
NSStringFromSelector(sel) |
Foundation | NSString * |
autoreleased | — | — | — | selector name as string |
@(expr).stringValue |
Foundation | NSString * |
autoreleased | — | — | — | boxed value → string |
Decision Flow #
Pure C, no runtime
├── Need a short-lived temp string?
│ └── mulle_sprintf_do(s, fmt, ...) { use s; }
├── Need a bounded fixed buffer?
│ └── mulle_snprintf(buf, sizeof(buf), fmt, ...)
├── Need a heap-allocated long-lived string?
│ └── mulle_asprintf(&p, fmt, ...) → mulle_free(p)
├── Building up incrementally / many appends?
│ └── mulle_buffer_do(buf) { mulle_buffer_sprintf(buf, ...); ... extract_string }
├── Just print to stdout / stderr?
│ └── mulle_printf(fmt, ...) / mulle_fprintf(stderr, fmt, ...)
└── Just a float to string?
└── mulle_dtostr(value, buf)
ObjC runtime available
├── Want autoreleased C string (no manual free)?
│ ├── MulleObjC_asprintf(fmt, ...)
│ └── mulle_buffer_do_autoreleased_string(buf, NULL, s) { build; }
├── Want autoreleased C string for a value type?
│ └── CGRectUTF8String(rect), etc.
├── Need an NSString (for containers, etc.)?
│ └── [NSString stringWithFormat:...]
└── Implementing -UTF8String?
└── mulle_buffer_do_autoreleased_string(buf, NULL, s) { format; } return s;
Memory-Management Rules of Thumb #
| Pattern | Free? | How? |
|---|---|---|
char buf[ N] + mulle_snprintf |
No | stack allocated |
mulle_asprintf(&p, ...) |
Yes | mulle_free(p) |
mulle_allocator_asprintf(a, &p, ...) |
Yes | via that allocator's free |
mulle_sprintf_do(s, ...) |
No | auto stack cleanup on block exit |
mulle_buffer_extract_string(buf) |
Yes | mulle_free(p) (or allocator's free) |
MulleObjC_asprintf(...) |
No | autoreleased — pool drain frees it |
mulle_buffer_do_autoreleased_string(...) |
No | autoreleased |
[NSString stringWithFormat:...] |
No | autoreleased |
-[NSString UTF8String] |
No | valid while NSString lives |
TypeUTF8String(...) |
No | autoreleased |
When Each Layer Is Available #
| Mechanism | Available where |
|---|---|
mulle_sprintf / mulle_asprintf / mulle_buffer_sprintf |
Everywhere (mulle-core / mulle-sprintf) |
mulle_printf / mulle_fprintf |
Everywhere (mulle-fprintf) |
mulle_buffer_do / mulle_buffer_extract_string |
Everywhere (mulle-buffer via mulle-core) |
mulle_sprintf_do |
Everywhere (macro in mulle-sprintf.h) |
MulleObjC_asprintf / MulleObjC_vasprintf |
Needs MulleObjC |
mulle_buffer_do_autoreleased_string |
Needs MulleObjC (MulleObjCPrinting.h) |
MulleObjCAutoreleaseAllocation |
Needs MulleObjC (NSAutoreleasePool) |
-[NSObject UTF8String] / -[NSObject description] |
Needs MulleObjC |
TypeUTF8String functions |
Per-library (MulleCG, MulleUIBase, etc.) |
[NSString stringWithFormat:] / [NSString stringWithUTF8String:] |
Needs MulleFoundation |
NSStringFromClass / NSStringFromSelector |
Needs MulleFoundation |
last updated: