News for hackers. Stuff that matters.
Re:Beej’s Guide to C Programming [pdf] by qsort on Friday April 23, 2021 @03:53AM (#26912206)
What's difficult to understand about pointers isn't the concept of a pointer itself, or even * and &, it's the fact that working with pointers requires you to simultaneously understand different abstraction levels. While it's not unique to pointers, and it's in fact the case for most nontrivial programming tasks, what's unique about C is that pointers are so pervasive you can't really do anything if you don't understand how to work with them.

IME languages like Python aren't any easier than C to work with (ignoring UB issues of course), but it's certainly the case that you can probably kinda sorta get your job done with Python even without understanding the first thing of what you're doing, and that's not happening if you write in C.

Re:Beej’s Guide to C Programming [pdf] by bluetomcat on Friday April 23, 2021 @04:15AM (#26912338)
In C, pointers require you to think deeply about the ownership and lifetime of any "allocated object" at runtime. How long does it live, who is responsible for the deallocation, how many pointers does your program hold to that object (dangling issues). Ultimately, it can lead to a cleaner design if these issues are taken seriously up-front.
Re:Beej’s Guide to C Programming [pdf] by qsort on Friday April 23, 2021 @04:36AM (#26912462)
I don't disagree with that, but most cases fall within a pretty clear pattern:

- typedef struct { ... } foo

- foo *foo_create()

- void foo_destroy(foo *)

- a bunch of functions that take foo* as their first arg

which is kind of the same as a class and only more error-prone.

I say this as someone who actually _likes_ C, but the manual memory management model is very often unnecessary, confusing, repetitive. There was an idea some time ago of a language extension that would extend the concept of automatic storage duration to allow an explicit destructor to be called when the variable goes out of scope, like <close> variables in some languages. I genuinely think things like that would make the language a bit more ergonomic without fundamentally changing its nature.

Re:Beej’s Guide to C Programming [pdf] by bluetomcat on Friday April 23, 2021 @05:07AM (#26912630)
That's why I tend to always prefer automatic and static storage to dynamic allocation wherever possible, especially in cases where you don't have "N" items or "N" cannot possibly exceed a certain small value. Also, allocation/deallocation of the certain object need not be defined within its module. It should be up to the caller to decide whether to allocate the object on the stack, statically or dynamically depending on the caller's situation:

    foo f;
    foo_init(&f);
    foo_destroy(&f);
    ...
    foo *g = malloc(sizeof(foo));
    foo_init(g);
    foo_destroy(g);
    free(g);
Re:Beej’s Guide to C Programming [pdf] by unwind on Friday April 23, 2021 @06:16AM (#26913053)
That is of course fine, with the drawback that it requires a public definition of the foo type.

I would write the allocation as

    foo * const g = malloc(sizeof *g);
to avoid repeating the type name and "lock" the allocation to the variable. If the type on the left hand side ever would change, this still does the right thing.
Re:Beej’s Guide to C Programming [pdf] by quelsolaar on Friday April 23, 2021 @06:16AM (#26913055)
Interesting, I tend to prefer a create and destroy function that allocates and frees the structure. That way you can have foo without it being initialized, and you cant have foo been freed without being de-initialized. Where do see the value in being able to move it between different memory types?
Re:Beej’s Guide to C Programming [pdf] by dahart on Friday April 23, 2021 @09:41AM (#26914661)
In games and embedded systems, a very common pattern is batched heap allocation: a single allocation of an array of foo, and/or an array of foo mixed with other types, or sometimes a memory managed data structure like a memory pool. This is one big reason that the C++ Standard Template Library was shunned in game studios for a long time; it automatically did it’s own heap allocations, sometimes at inopportune times IIRC like in constructors, and didn’t let the caller choose. EA wrote their own version (EASTL) that was game friendly because it allowed control of the allocator.

In GPU programming, there are actual different memory sub-systems, with different sizes and different performance implications, so it’s critical that the caller is able to do the allocation & deallocation any way they want. This is why most well designed GPU APIs rarely allocate GPU memory inside the API, but instead are designed to work with caller-provided pointers to buffers.

Re:Beej’s Guide to C Programming [pdf] by TorKlingberg on Friday April 23, 2021 @06:52AM (#26913322)
Coming from the embedded world, I am far more used to the style bluetomcat showed where the caller handles allocation. It takes more work to use, and you have to make sure to not use it before initializing or after destroying, as you said. The advantage is that the caller has full control of memory allocation. The object can be a local variable, a static, malloc:ed, come from a custom allocator (say a slab allocator), or be a part of a larger struct.
Re:Beej’s Guide to C Programming [pdf] by quelsolaar on Friday April 23, 2021 @10:09AM (#26914937)
That makes a lot of sense. I do some embedded development, but when I dont, I tend to prefer heap just because my memory debuggers are much more capable working with heap memory.

In the case you show, foo would have to be a struct that doesn't contain pointers to additional allocated memory, but its a entirely valid use case and pattern.

Calling malloc and free, has a cost associated with it, that the stack doesn't. But stack can in some cases, like with recursion be scary to use, because you dont know where it ends. If malloc returns NULL you know you have found the end and can do something reasonable.

Thanks for you insight!

Re:Beej’s Guide to C Programming [pdf] by krychu on Friday April 23, 2021 @05:15PM (#26919291)
I always lacked a good discussion on the subject of allocation/deallocation strategies. Is there some recommended good read?
Re:Beej’s Guide to C Programming [pdf] by alexhutcheson on Friday April 23, 2021 @11:39AM (#26915848)
It’s not standardized, but if you’re using gcc, you can use the cleanup attribute for this: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attribute...

IIRC clang implements it as well, but I wasn’t able to find a reference to it in their docs.

Re:Beej’s Guide to C Programming [pdf] by AlbertoGP on Friday April 23, 2021 @05:28AM (#26912771)
I’m actually implementing that right now for my own use, as a pre-processor.

There is a much more advanced design and implementation at “A defer mechanism for C” (December 2020): https://gustedt.wordpress.com/2020/12/14/a-defer-mechanism-f...

For my own purposes, I think I can live without handling stack unwinding so I continue working on my pre-processor.

Since the pre-processor is not yet finished, there I use a vector¹ of {.pointer, .destructor} where I put objects after initialization, with one macro at the end of each managed scope that calls the destructors for that scope in reverse order, then another macro meant for the function exit points that calls all the destructors in that vector. This has been built many times before by other people of course, it’s just an exercise to see which difficulties arise.

¹ Vector, growable array: I did my own trivial type-generic growable array, with the classic {.capacity, .len, .items}, but again there are many previous implementations. The two I’ve found more interesting are:

- “C Template Library (CTL)”: https://github.com/glouw/ctl

- “Klib: a Generic Library in C”: https://github.com/attractivechaos/klib/

Re:Beej’s Guide to C Programming [pdf] by tirrex on Friday April 23, 2021 @02:13PM (#26917510)
For a vector alternative, I find this one easy to read and use :

https://github.com/tezc/sc/tree/master/array

It is just an array of your type, e.g int *numbers, so you have type info in debugger as well.

Re:Beej’s Guide to C Programming [pdf] by Arch-TK on Friday April 23, 2021 @07:15PM (#26920363)
No type safety and broken alignment. No thanks.
Re:Beej’s Guide to C Programming [pdf] by tirrex on Friday April 23, 2021 @07:39PM (#26920572)
Isn’t it type safe? e.g you can’t add char* to a double array.

What do you mean by broken alignment?

Re:Beej’s Guide to C Programming [pdf] by Arch-TK on Saturday April 24, 2021 @04:51AM (#26923400)
It lacks type safety because it's not possible to distinguish between an sc_array and a pointer so there's no way of detecting that someone passed a char * that nobody had ever called sc_array_create on to sc_array_add for example.

The alignment is broken because nothing in the C standard guarantees that the elems member of sc_array will be aligned correctly for any possible element type.

I also spotted another problem, in sc_array_init the code `void *p = a` is also not guaranteed to work. In an example snippet such as `int iv; sc_array_create(iv, 0);` expands to `sc_array_init(&iv, sizeof iv, 0)` so the type of the expression `&iv` is `int *` which is then being converted to `void *` in the function which is actually not allowed by the standard. This is also the reason why if you were writing a wrapper around realloc which exited if the allocation failed you would still have to pass in the current pointer with void * and return the new pointer with void *. This could be applied here actually as an easy fix but it indicates even further to me that the author of the library is taking a very leisurely approach to writing conforming C. This pattern also appears in the other two functions though and I'm not sure if in those cases it's something which can be easily fixed.

Re:Beej’s Guide to C Programming [pdf] by glouwbug on Friday April 23, 2021 @12:00PM (#26916104)
With a bit of trickery CTL works much like the STL, in that containers can be built of containers:

    #define P
    #define T int
    #include <vec.h>

    #define T vec_int
    #include <deq.h>
A deq_vec_int - analogous to std::deque<std::vector<int>> - is a neat example.
Re:Beej’s Guide to C Programming [pdf] by cygx on Friday April 23, 2021 @12:45PM (#26916577)
There's also a CTL fork that might be of interest: https://github.com/rurban/ctl
Re:Beej’s Guide to C Programming [pdf] by oscargrouch on Friday April 23, 2021 @04:45PM (#26919006)
I also like the Ken Thompson extensions from which part of Go was inspired by

    struct X { int a; }
    struct Y { *X; int b; int c;}

    void add(Y* self, int number) {
      self->a += number;
    }

    Y y;
    y.a = 10; // composition
    y.add(1) // y.a = 11 now
This alone would simplify C coding so much without taking any power out of it.

The other extension i would add is some sort of interface or protocol.

As soon as you can do something like "y.add(1)", having a generic contract to refer to things without having to know its concrete type is some of the good things from the OOP world.

With this you would also be able to call some cleanup code and even a initializer.

This is still C and its still much simpler than C++, and yet almost as powerful.

C should propose these kind of things even if it was not that conservative and it would retain a lot of coders that migrate instead giving C barely evolved from its 70's roots.

Re:Beej’s Guide to C Programming [pdf] by Joker_vD on Friday April 23, 2021 @08:41AM (#26914119)
Yeah, except when it doesn't follow the pattern: for example, there is no foo_destroy(), you're supposed to "just" call free() when you're done with it. Used to be very common (not sure how it is now), and very frustrating when you link against non-standard allocators.
Re:Beej’s Guide to C Programming [pdf] by jhgb on Friday April 23, 2021 @05:13AM (#26912677)
> In C, pointers require you to think deeply about the ownership and lifetime of any "allocated object" at runtime.

Unless you decide you use libgc, presumably?

Re:Beej’s Guide to C Programming [pdf] by unwind on Friday April 23, 2021 @04:25AM (#26912394)
These are good points. I can sometimes feel that Python is more pointer-y (?) than people expect, with stuff like:

    a = {"one": 1, "two": 2 }
    b = a
    b["two"] = 99
    print(a["two"])
The above prints 99, since "b = a" does not copy the value (the dictionary) but just the reference to the value ("the pointer", kind of). This is surprising to some people.
Re:Beej’s Guide to C Programming [pdf] by qsort on Friday April 23, 2021 @04:50AM (#26912540)
I agree, which is why I'm glad the first language I learned was C. I don't get to write a lot of C at work, but the concepts the language teaches you are the very fundamentals of programming.

I know it's probably baseless, but I can't shake the feeling that people who learn modern languages before learning C are just making their own lives harder.

Re:Beej’s Guide to C Programming [pdf] by bregma on Friday April 23, 2021 @07:27AM (#26913551)
I think the same goes for learning assembly before learning C. A simple assembly-based computer [1] should be the first programming target in every "introduction to programming" class. After that, C becomes obvious and those who struggle with the fundamntals can be guided to more appropriate careers instead of dumbing down the tools everyone uses.

[0] https://www.instructables.com/CARDIAC-CARDboard-Illustrative...

Re:Beej’s Guide to C Programming [pdf] by ryl00 on Friday April 23, 2021 @09:06AM (#26914351)
This is one part (of many) of perl that I like, that it exposes the pointer-y parts to the programmer (to abuse :))

    # hash
    my %a = ( 'one' => 1, 'two' => 2 );
    my %b = %a;

    $b{ 'two' } = 99;

    # prints 2
    print $a{ 'two' }, "\n";

    # reference to hash
    my $a = { 'one' => 1, 'two' => 2 };
    my $b = $a;

    $b->{ 'two' } = 99;

    # prints 99
    print $a->{ 'two' }, "\n";
Re:Beej’s Guide to C Programming [pdf] by deckard1 on Friday April 23, 2021 @01:42PM (#26917197)
The real difference is Perl has typed variables, such as hashes or arrays, which other languages typically do not. Which does make it convenient when you need to clone the object, such as "%b = %a" example. Perl borrows the sigil concept from Bash and other shells (which makes sense, given the historical context of Perl). The only other language I know of that uses sigils in such manner is BASIC. Other languages, such as Ruby or Common Lisp, use them as syntactic convention rather than as a feature that the compiler/interpreter understands.[1]

Most dynamic languages expose the data as references. In fact, the one thing that trips up JavaScript developers (especially in React) is that they do not understand how references work. I see senior and lead developers inadvertently doing mutation all the time. Or getting incredibly paranoid that two identical strings, for example, do not equal each other in the strictest sense in JS. They also throw in memoization everywhere due to their fundamental lack of understanding.

You can always tell the developers that do not have C/C++/Pascal experience.

[1] https://en.wikipedia.org/wiki/Sigil_(computer_programming)

Re:Beej’s Guide to C Programming [pdf] by skocznymroczny on Friday April 23, 2021 @06:17AM (#26913065)
Reminds me of the Python trap that I fall into every few months because I forget about it:

def foo(mylist=[]): mylist.append("a") return mylist

mylist is only initialized once, so the function will actually return one more "a" with each function execution

Re:Beej’s Guide to C Programming [pdf] by klyrs on Saturday April 24, 2021 @12:41PM (#26926218)
It's a feature! Use this memoization pattern and you'll never forget it

  def foo(x, cache={}):
    if x in cache:
      return cache[x]
    val = cache[x] = x*x+1
    return val
But, be warned, there's no mechanism for cache eviction; use @lru_cache if you don't know ahead of time that x will take a reasonably small number of values
Re:Beej’s Guide to C Programming [pdf] by serial_dev on Friday April 23, 2021 @05:16AM (#26912685)
It's also similar in Java's pass-by-value vs pass-by-reference (pass as well as copy), if I recall correctly.
Re:Beej’s Guide to C Programming [pdf] by kaba0 on Friday April 23, 2021 @06:06AM (#26912994)
Actually, most languages only have pass-by-value, being “pedantic” (but it is actually a useful distinction). I’m sure there are other’s but out of the majorly used languages, only C++ has actual references. Pointers are passed by value, that is the pointer value gets copied. References are a language level construct.

Here is a great “rant” at it in case of Java:

http://www.javadude.com/articles/passbyvalue.htm

Re:Beej’s Guide to C Programming [pdf] by bluedino on Friday April 23, 2021 @12:07PM (#26916182)
People that can’t comprehend arrays/lists in Python, especially multi-dimensional ones, would have had no chance in C