Code Monkey home page Code Monkey logo

libcsptr's Introduction

C Smart Pointers

Build Status Coverage Status License Version

What this is

This project is an attempt to bring smart pointer constructs to the (GNU) C programming language.

Features

  • unique_ptr, shared_ptr macros, and smart type attribute
  • Destructor support for cleanup
  • Custom variable metadata on allocation
  • Cross-platform: tested under linux 3.18.6-1, Mac OS X Yosemite 10.10, and Windows 7 (with MinGW and the Cygwin port of GCC)

Installing

With a package manager

  • Mac OS X: brew install snaipe/soft/libcsptr

  • AUR: yaourt -S libcsptr

  • Ubuntu:

    $ sudo add-apt-repository ppa:snaipewastaken/ppa
    $ sudo apt-get update
    $ sudo apt-get install libcsptr-dev

Building from source

Prerequisites

To compile the library, GCC 4.6+ is needed.

Installation

  1. Clone this repository
  2. run mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=$HOME .. && make && make install
    from the project root for a local install, or run
    mkdir build && cd $_ && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make && sudo make install for a global install.

Examples

  • Simple unique_ptr: simple1.c:
    #include <stdio.h>
    #include <csptr/smart_ptr.h>
    
    int main(void) {
        // some_int is an unique_ptr to an int with a value of 1.
        smart int *some_int = unique_ptr(int, 1);
    
        printf("%p = %d\n", some_int, *some_int);
    
        // some_int is destroyed here
        return 0;
    }
    Shell session:
    $ gcc -std=c99 -o simple1 simple1.c -lcsptr
    $ valgrind ./simple1
    ==3407== Memcheck, a memory error detector
    ==3407== Copyright (C) 2002-2013, and GNU GPL\'d, by Julian Seward et al.
    ==3407== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
    ==3407== Command: ./test1
    ==3407==
    0x53db068 = 1
    ==3407==
    ==3407== HEAP SUMMARY:
    ==3407==     in use at exit: 0 bytes in 0 blocks
    ==3407==   total heap usage: 1 allocs, 1 frees, 48 bytes allocated
    ==3407==
    ==3407== All heap blocks were freed -- no leaks are possible
    ==3407==
    ==3407== For counts of detected and suppressed errors, rerun with: -v
    ==3407== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
  • Simple unique_ptr with destructor:
    #include <unistd.h>
    #include <fcntl.h>
    #include <csptr/smart_ptr.h>
    
    struct log_file {
        int fd;
        // ...
    };
    
    void cleanup_log_file(void *ptr, void *meta) {
        (void) meta;
        close(((struct log_file *) ptr)->fd);
    }
    
    int main(void) {
        smart struct log_file *log = unique_ptr(struct log_file, {
                .fd = open("/dev/null", O_WRONLY | O_APPEND),
                // ...
            }, cleanup_log_file);
    
        write(log->fd, "Hello", 5);
    
        // cleanup_log_file is called, then log is freed
        return 0;
    }
  • Allocating a smart array and printing its contents before destruction:
    #include <stdio.h>
    #include <csptr/smart_ptr.h>
    #include <csptr/array.h>
    
    void print_int(void *ptr, void *meta) {
        (void) meta;
        // ptr points to the current element
        // meta points to the array metadata (global to the array), if any.
        printf("%d\n", *(int*) ptr);
    }
    
    int main(void) {
        // Destructors for array types are run on every element of the
        // array before destruction.
        smart int *ints = unique_ptr(int[5], {5, 4, 3, 2, 1}, print_int);
        // ints == {5, 4, 3, 2, 1}
    
        // Smart arrays are length-aware
        for (size_t i = 0; i < array_length(ints); ++i) {
            ints[i] = i + 1;
        }
        // ints == {1, 2, 3, 4, 5}
    
        return 0;
    }

More examples

  • Using a different memory allocator (although most will replace malloc/free):

    #include <csptr/smart_ptr.h>
    
    void *some_allocator(size_t);
    void some_deallocator(void *);
    
    int main(void) {
        smalloc_allocator = (s_allocator) {some_allocator, some_deallocator};
        // ...
        return 0;
    }
  • Automatic cleanup on error cases:

    #include <unistd.h>
    #include <fcntl.h>
    #include <csptr/smart_ptr.h>
    
    struct log_file {
        int fd;
        // ...
    };
    
    static void close_log(void *ptr, void *meta) {
        (void) meta;
        struct log_file *log = ptr;
        if (log->fd != -1)
            close(log->fd);
    }
    
    struct log_file *open_log(const char *path) {
        smart struct log_file *log = shared_ptr(struct log_file, {0}, close_log);
        if (!log) // failure to allocate
            return NULL; // nothing happens, destructor is not called
    
        log->fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644);
        if (log->fd == -1) // failure to open
            return NULL; // log gets destroyed, file descriptor is not closed since fd == -1.
    
        return sref(log); // a new reference on log is returned, it does not get destoyed
    }
    
    int main(void) {
        smart struct log_file *log = open_log("/dev/null");
        // ...
        return 0; // file descriptor is closed, log is freed
    }
  • Using named parameters:

    #include <csptr/smart_ptr.h>
    
    void nothing(void *ptr, void *meta) {}
    
    int main(void) {
        struct { int a; } m = { 1 };
    
        smart int *i = unique_ptr(int,
                .dtor = nothing,
                .value = 42,
                .meta = { &m, sizeof (m) }
            );
    
        return 0;
    }

FAQ

Q. Why didn't you use C++ you moron ?
A. Because when I first started this, I was working on a C project. Also, because it's fun.

Q. Can I use this on a serious project ?
A. Yes, but as this project has not been widely used, there might be some bugs. Beware!

Q. How did you make this ?
A. Here's a link to my blog post on the matter.

libcsptr's People

Contributors

anupamaggarwal avatar avinassh avatar badoum92 avatar hizel avatar snaipe avatar steve384 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libcsptr's Issues

Tests fail to compile: error: function definition is not allowed here, etc

[ 11% 6/9] /usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/misc.c.o -MF check/CMakeFiles/check_unit.dir/test/misc.c.o.d -o check/CMakeFiles/check_unit.dir/test/misc.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c
FAILED: check/CMakeFiles/check_unit.dir/test/misc.c.o 
/usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/misc.c.o -MF check/CMakeFiles/check_unit.dir/test/misc.c.o.d -o check/CMakeFiles/check_unit.dir/test/misc.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c:14:42: error: function definition is not allowed here
        lambda(void *, (UNUSED size_t s) { return NULL; }),
                                         ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c:14:9: error: use of undeclared identifier '__fn__'
        lambda(void *, (UNUSED size_t s) { return NULL; }),
        ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:51: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                                                  ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c:15:41: error: function definition is not allowed here
        lambda(void, (UNUSED void *ptr) {})
                                        ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c:15:9: error: use of undeclared identifier '__fn__'
        lambda(void, (UNUSED void *ptr) {})
        ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:51: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                                                  ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c:14:9: error: initializing 'void *(*)(size_t)' (aka 'void *(*)(unsigned long)') with an expression of incompatible type 'void'
        lambda(void *, (UNUSED size_t s) { return NULL; }),
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:29: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/misc.c:15:9: error: initializing 'void (*)(void *)' with an expression of incompatible type 'void'
        lambda(void, (UNUSED void *ptr) {})
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:29: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 errors generated.
[ 22% 6/9] /usr/bin/cc -Dcsptr_EXPORTS -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/include/csptr -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/src -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -fPIC   -fPIC -MD -MT CMakeFiles/csptr.dir/src/array.c.o -MF CMakeFiles/csptr.dir/src/array.c.o.d -o CMakeFiles/csptr.dir/src/array.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/src/array.c
[ 33% 6/9] /usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/scalar.c.o -MF check/CMakeFiles/check_unit.dir/test/scalar.c.o.d -o check/CMakeFiles/check_unit.dir/test/scalar.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c
FAILED: check/CMakeFiles/check_unit.dir/test/scalar.c.o 
/usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/scalar.c.o -MF check/CMakeFiles/check_unit.dir/test/scalar.c.o.d -o check/CMakeFiles/check_unit.dir/test/scalar.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c:13:76: error: function definition is not allowed here
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                                                                           ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c:13:25: error: use of undeclared identifier '__fn__'
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                        ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:51: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                                                  ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c:13:18: error: initializing 'f_destructor' (aka 'void (*)(void *, void *)') with an expression of incompatible type 'void'
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                 ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c:30:76: error: function definition is not allowed here
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                                                                           ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c:30:25: error: use of undeclared identifier '__fn__'
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                        ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:51: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                                                  ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/scalar.c:30:18: error: initializing 'f_destructor' (aka 'void (*)(void *, void *)') with an expression of incompatible type 'void'
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                 ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 errors generated.
[ 44% 6/9] /usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/shared.c.o -MF check/CMakeFiles/check_unit.dir/test/shared.c.o.d -o check/CMakeFiles/check_unit.dir/test/shared.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/shared.c
FAILED: check/CMakeFiles/check_unit.dir/test/shared.c.o 
/usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/shared.c.o -MF check/CMakeFiles/check_unit.dir/test/shared.c.o.d -o check/CMakeFiles/check_unit.dir/test/shared.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/shared.c
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/shared.c:13:76: error: function definition is not allowed here
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                                                                           ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/shared.c:13:25: error: use of undeclared identifier '__fn__'
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                        ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/utils.h:40:51: note: expanded from macro 'lambda'
#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
                                                  ^
/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/shared.c:13:18: error: initializing 'f_destructor' (aka 'void (*)(void *, void *)') with an expression of incompatible type 'void'
    f_destructor dtor = lambda(void, (UNUSED void *ptr, UNUSED void *meta) { dtor_run = 1; });
                 ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 errors generated.
[ 55% 6/9] /usr/bin/cc  -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/../include -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -MD -MT check/CMakeFiles/check_unit.dir/test/test.c.o -MF check/CMakeFiles/check_unit.dir/test/test.c.o.d -o check/CMakeFiles/check_unit.dir/test/test.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/check/test/test.c
[ 66% 6/9] /usr/bin/cc -Dcsptr_EXPORTS -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/include/csptr -I/disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/src -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -Wall -Wextra -Werror -g -std=gnu99 -Wno-unused-result -Wno-missing-field-initializers -O2 -pipe -fno-omit-frame-pointer  -fstack-protector-strong -isystem /usr/local/include -fno-strict-aliasing -fPIC   -fPIC -MD -MT CMakeFiles/csptr.dir/src/mman.c.o -MF CMakeFiles/csptr.dir/src/mman.c.o.d -o CMakeFiles/csptr.dir/src/mman.c.o -c /disk-samsung/freebsd-ports/devel/libcsptr/work/libcsptr-2.0.4-24-gac73451/src/mman.c
ninja: build stopped: subcommand failed.

Rev. ac73451
clang-13
FreeBSD 13.1

How can you implement the great smart attribute?!

It's so wonderful that you implement the smart type attribute!
Could you tell me how you did this? I can't find doc related to user defined type attribute for C/C++, but only user defined type.
Thank you very much!

Trying to understand the two available options more clearly

In the build descriptionf file, you define two custom options - one for a variadic sentinel, the other to always use malloc. This might sound stupid, but what's the idea behind that? I'm basically trying to understand your code, and this is currently eluding me. Could you please help me understand?

Fail to compile

I can't compile the project. Here is the output:

/tmp/libcsptr/check/test/utils.h: In function ‘make_test_case’:
/tmp/libcsptr/check/test/utils.h:26:28: error: passing argument 2 of ‘_tcase_add_test’ from incompatible pointer type [-Werror=incompatible-pointer-types]
26 | tcase_add_test(tc, f);
| ^
| |
| TFun {aka void (
)(int)}
/usr/include/check.h:331:69: note: expected ‘const TTest *’ {aka ‘const struct TTest ’} but argument is of type ‘TFun’ {aka ‘void ()(int)’}
331 | CK_DLL_EXP void CK_EXPORT _tcase_add_test(TCase * tc, const TTest * ttest,
| ~~~~~~~~~~~~~~^~~~~
cc1: all warnings being treated as errors

However without libcheck installed, I can compile without problem

Suggestion on smart arrays

Firstly, I must commend you on a very nice library here. Creating a library for smarter pointers in C and doing it in a way that is compatible with the syntax and style of the language is a real step forward for people like me who want to try high-level programming in C. Keep up the good work, and I'd be curious to hear if you have any plans for further features/updates. (I like that it's a small library right now though, and quite minimalistic as is C as a whole.)

Regarding "smart arrays" specifically: I like that the library can infer the size of fixed-size arrays and use this to automate the destructor more. However, I personally imagine that implementing this in another way would be more general and extensible:

  1. For any fixed-size array type, set the default metadata to a size_t containing that size, and also set the default destructor to a function that does sfree on each element of the array (if the element type is a pointer) and nothing (if the element type is a non-pointer).
  2. Allow the metadata and destructor for the array to be override the defaults when they are specified as normal in the unique_ptr or shared_ptr macro call.

Anyway, let me know what you think, and maybe we can establish what sort of interface for smart arrays is best. The design of the library in general is great, of course. :)

sentinel uneeded in variadic macro pattern

The use of the sentinel in the variadic macro pattern is not necessary. The following is valid C and compiles using both gcc-4.4.7 and clang-3.4.2.

edit: Clang also produces no compiler warnings at -Wextra. I understand the desire to maintain ISO compatibility, however, this was not apparent as other GCC/Clang extensions are used, such as the named variadic macro.

edit2: missing context from blog post:

Because the cleanup attribute is a compile time feature, I was going to play around with this on an embedded system like an AVR chip or similar target, where every single bit of RAM counts (most of my stock of AVR chips are 128-512 bytes of ram).

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define valloc( T, ...)                \
    ({                                  \
        struct _tmp {                   \
            __typeof__(T) value;        \
        } args = {                      \
            __VA_ARGS__                        \
        };                              \
        void * new = malloc(sizeof(T));  \
        if ( new != NULL)               \
            memcpy( new, &args.value, sizeof(T)); \
        new;                        \
    })

struct vfunc_params {
    int a;
};

void vfunc_real( struct vfunc_params *args) {
    printf("vfunc_param->a = %#x\n", args->a);
}

#define vfunc(...) \
    vfunc_real( &(struct vfunc_params) { __VA_ARGS__ })

int main( int argc, char * argv[])
{
    int * x = 0;

    x = valloc( int );
    printf("valloc returned -> %#x\n", *x);
    free(x);

    x = valloc( int, 0xBAD0BEEF);
    printf("valloc returned -> %#x\n", *x);
    free(x);

    vfunc();
    vfunc(42);

    return 0;
}

How to understand get_meta

size_t* size = (size_t *)ptr - 1;
return (s_meta *)((char *)size - *size);

why first -1, and (char*)size - *size means what?

A comment on ref-counting

In the blog post you wrote:

lock-free implementations [of refcounting] rely on a compare-and-swap mechanism on the wrapped pointer – here, the pointer is not wrapped. This sucks, but if we make the assumption that no destruction shall happen during an async context, it’s kind of fine

This doesn’t make sense to me. I’ve implemented ref-counting a few times; it uses atomic increment/decrement of the refcount field, not the pointer to the object. When the decremented refcount hits zero you free the object, with no thread-safety issues because by definition only the current thread has a reference to it.

This assumes an “intrusive refcount” stored in the object's metadata. The C++ shared_ptr avoids that but it requires allocating a separate block containing the refcount and a pointer to the object, and the shared_ptr itself is a pointer to that block. That seems far too awkward to use in C since it required a double dereference.

Support structs with flexible array members?

I'd like to extend libcsptr (specifically, the shared_ptr/unique_ptr macros) to handle C99 structs with flexible array members.

I. e.

struct Foo
{
    size_t size;
    char data[];
}

struct Foo *foop = shared_flex(struct Foo, ...);

Easy enough on the surface (add a member + length parameters and calculate the allocation size with a few offsetof and sizeof calls) and so far I came up with this implementation:

#define smart_flex(Kind, Type, Member, Length, ...)                         \
    ({                                                                      \
        struct s_tmp {                                                      \
            CSPTR_SENTINEL_DEC                                              \
            __typeof__(Type) value;                                         \
            f_destructor dtor;                                              \
            struct {                                                        \
                const void *ptr;                                            \
                size_t size;                                                \
            } meta;                                                         \
        } args = {                                                          \
            CSPTR_SENTINEL                                                  \
            __VA_ARGS__                                                     \
        };                                                                  \
        const size_t alloc_size =                                           \
            offsetof (Type, Member)                                         \
            + sizeof (((Type *)0)->Member[0]) * (Length);                   \
        void *var = smalloc(alloc_size, 0, Kind, ARGS_);                    \
        if (var != NULL)                                                    \
            memcpy(var, &args.value, sizeof (Type));                        \
        var;                                                                \
    })

However, including a struct with a flexible array member as a non-last member of another struct is a (now-deprecated) gcc extension.

Any ideas on how to do this properly and preserve the ergonomics of accepting an optional destructor + metadata at the end of the smart_flex() call?

not support MSVC

We use C in windows with MSVC compiler, but __attribute__((cleanup)) does not work in MSVC. Is is possible to support MSVC?

Requiring smart pointers to be initialized

In C++, unique_ptr and shared_ptr require a value, since they have ownership over it -- but in this case, since we don't wrap a pointer but return actual unintialized memory, I was wondering if the unique_ptr and shared_ptr macro should take a mandatory value and initialize the memory with it.

Usage would be:

smart int *some_int = unique_ptr(int, (1));
smart double *some_array = unique_ptr(double[4], ({1, 2.5, 3.2, 0.999}), some_dtor);
smart long *some_zero_padded_array = unique_ptr(long[25], ({1}), &some_meta, sizeof (some_meta));

struct { 
    int a;
    long b;
    double c;
} s;
smart struct s *some_struct = unique_ptr(struct s, ({ .a = 1, .b = 2 }), dtor, &some_meta, sizeof (some_meta));

Parenthesis over the value are unfortunate, but would be mandatory to allow struct and array literals to be passed, since curly braces are known to not group commas together in macro parameters.

I am still not sure about that to be honest since one could desire to initialize the memory in a more specific way, but to be fair, that's what smalloc should be for.

atomic_add impl report error by ThreadSanitizer

hello,
I learn a lot from you project,
When I write a multi-thread program and test.
I use tsan to check data race, reports error:

0x7b0c00000328
==================
WARNING: ThreadSanitizer: data race (pid=48322)
  Read of size 8 at 0x7b0c00000318 by thread T1:
    #0 sref mman.c:91 (a.out:x86_64+0x100002c47)
    #1 thr main.c:16 (a.out:x86_64+0x100002655)
old_count: 2
  Previous atomic write of size 8 at 0x7b0c00000318 by main thread:
    #0 sref mman.c:91 (a.out:x86_64+0x100002c95)
    #1 main main.c:31 (a.out:x86_64+0x1000027a6)
old_count: 2
  Location is heap block of size 48 at 0x7b0c00000300 allocated by main thread:
    #0 malloc <null>:188732607 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x55a7c)
    #1 smalloc_impl mman.c:163 (a.out:x86_64+0x10000349d)
    #2 smalloc mman.c:212 (a.out:x86_64+0x100003341)
    #3 main main.c:26 (a.out:x86_64+0x1000026ed)

  Thread T1 (tid=486984, running) created by main thread at:
    #0 pthread_create <null>:188732607 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x3155f)
    #1 main main.c:30 (a.out:x86_64+0x100002794)

there is a simple demo just for test:

#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <csptr/smart_ptr.h>

struct T {
    int foo;
};

static void cleanupfunc(void *ptr, void *meta) {
    printf("cleanupfunc\n");
}

void *thr(void *p)
{
    sref(p);
    sfree(p);
    return NULL;
}

int main()
{
    pthread_t t1;
    pthread_t t2;
    pthread_t t3;
    smart struct T *p = shared_ptr(struct T, {}, cleanupfunc);
    
    sref(p);
    pthread_create(&t1, NULL, thr, p);
    sref(p);
    pthread_create(&t2, NULL, thr, p);
    sref(p);
    pthread_create(&t3, NULL, thr, p);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    sfree(p);
    sfree(p);
    sfree(p);
}

I check the code, found maybe the non-sync access for count ,

libcsptr/src/mman.c

Lines 43 to 52 in ac73451

static CSPTR_INLINE size_t atomic_add(volatile size_t *count, const size_t limit, const size_t val) {
size_t old_count, new_count;
do {
old_count = *count;
if (old_count == limit)
abort();
new_count = old_count + val;
} while (!__sync_bool_compare_and_swap(count, old_count, new_count));
return new_count;
}

But in think it not a real issue ,unless in x64. I got a way to avoid from abort of tsan, is it just make it happier?

static CSPTR_INLINE size_t atomic_add(volatile size_t *count, const size_t limit, const size_t val) {
    size_t old_count, new_count;
    do {
      old_count = __sync_fetch_and_add(count, 0);
      if (old_count == limit)
          abort();
      new_count = old_count + val;
    } while (!__sync_bool_compare_and_swap(count, old_count, new_count));
    return new_count;
}

also commit :
983932

missing common.h

Hi,
it seems, that the make && make install does not copy the common.h into the include directory, so that including smart_ptr.h in an application fails:

`In file included from vdpau_private.h:40:0,
from handles.c:23:
/usr/local/include/csptr/smart_ptr.h:29:21: fatal error: common.h: No such file or directory

include "common.h"

                 ^

compilation terminated.`

Copying common.h manually solved the problem here. The three other *.h are there ...

Regards
rellla

Problem with ... error: invalid conversion from ‘void*’ to ‘void**’

I was getting

/usr/include/csptr/smart_ptr.h: In function ‘void sfree_stack(void*)’:
/usr/include/csptr/smart_ptr.h:33:23: error: invalid conversion from ‘void*’ to ‘void**’ [-fpermissive]
     void **real_ptr = ptr;
                       ^
make: *** [src/Test.o] Error 1

which I fixed by changing line
void **real_ptr = ptr;
to
void **real_ptr = (void**)ptr;

Q. Why didn't you use C++ you moron?

Q. Why didn't you use C++ you moron?

A. Because C makes smaller and faster executables. There is no ABI which is not made for C. Using C, I can focus on the job done. Using C++, one first has to satisfy the language[1], and just then one can try and get the job done.

defer is coming into ISO C (gasp!) Good read for us C "morons", who use clang or gnuc __cleanup__

[1] What do I mean by "satisfy the language"? motivation section of this paper explains it clearly

Reassignement ?

I am a big fan of bringing unique_ptr to GNU C. But I think there is a difference beetween your repo and the cpp standard: reading this https://en.cppreference.com/w/cpp/memory/unique_ptr/operator%3D
What happens if I reassign a value ? Is this GNU-C undefined behaviour ?

Reading the exemples, you never return unique_ptr from functions. Again, if it is not possible, it is a key difference with c++ unique_ptr.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.