News for hackers. Stuff that matters.
Re:Everything I wish I knew when learning C by derefr on Monday November 28, 2022 @12:49PM (#33776828)
> There's no particular reason why C doesn't allow you to assign one array to another of the same length, it's largely just an arbitrary restriction.

IIRC C has an informal guarantee that no primitive syntax will ever cause the CPU to do more than O(1) work at runtime. Assignment is always O(1), and therefore assignment is limited to scalars. If you need assignment that might do O(N) work, you need to call a stdlib function (memcpy/memmove) instead. If you need an allocation that might do O(N) work, you either need a function (malloc) or you need to do your allocation not-at-runtime, by structuring the data in the program's [writable] data segment, such that it gets "allocated" at exec(2) time.

This is really one of the biggest formal changes between C and C++ — C++ assignment, and keywords `new` and `delete`, can both do O(N) work.

(Before anyone asks: a declaration `int foo[5];` in your code doesn't do O(N) work — it just moves the stack pointer, which is O(1).)

Re:Everything I wish I knew when learning C by leni536 on Monday November 28, 2022 @01:28PM (#33777454)
This reasoning falls apart for structs with array members.
Re:Everything I wish I knew when learning C by DSMan195276 on Monday November 28, 2022 @02:49PM (#33778602)
> Assignment is always O(1)

This depends on what you consider to be O(1) - being that the size of the array is fixed it's by definition O(1) to copy it, but I might get your point. I think in general your point isn't true though, C often supports integer types that are too large to be copied in a single instruction on the target CPU, instead it becomes a multi-instruction affair. If you consider that to still be O(1) then I think it's splitting hairs to say a fixed-size array copy would be O(N) when it's still just a fixed number of instructions or loop iterations to achieve the copy.

Beyond that, struct assignments can already generate loops of as large a size as you want, Ex: https://godbolt.org/z/8Td7PT4af

Re:Everything I wish I knew when learning C by LegionMammal978 on Monday November 28, 2022 @06:02PM (#33781125)
I think the meaning here is that assignment is never O(N) for any variable N computed at runtime. Of course, you can create arbitrarily large assignments at compile time, but this always has an upper bound for a given program.
Re:Everything I wish I knew when learning C by enedil on Monday November 28, 2022 @08:28PM (#33782493)
Then you are wrong, since we're already talking about arrays of sizes known at compile time. Indeed, otherwise we would also need to remember the size in the runtime.
Re:Everything I wish I knew when learning C by IgorPartola on Monday November 28, 2022 @10:13PM (#33783259)
IIRC this is valid in C99:

    void foo(size_t n) {
        int arr[n];
        …
    }
Re:Everything I wish I knew when learning C by LegionMammal978 on Monday November 28, 2022 @11:08PM (#33783583)
VLAs can be declared in a single statement, but they cannot be initialized in C17 (6.7.9):

> The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.

Curiously, C23 actually seems to break the O(1) rule, by allowing VLAs to be initialized with an empty initializer:

  int arr[n] = {};
GCC generates a memset call (https://godbolt.org/z/5v31bKs5a) to fill the array with zeros.
Re:Everything I wish I knew when learning C by throwaway2037 on Tuesday November 29, 2022 @05:29AM (#33785826)
How do you think it works? Does the compiler generate some kind of stack alloc?

Stupid question: Does that mean a huge value for 'n' can cause stack overflow at runtime? I recall that threads normally get a fixed size stack size, e.g., 1MB.

Re:Everything I wish I knew when learning C by IgorPartola on Tuesday November 29, 2022 @06:44AM (#33786333)
It just moves the stack pointer by n which is O(1). It doesn’t initialize it of course. But my point is that the array size isn’t known at compile time.
Re:Everything I wish I knew when learning C by jcelerier on Tuesday November 29, 2022 @10:43AM (#33788911)
Yes, it causes stack overflow at runtime. Compilers warn for it, in particular clang has a warning that you can configure to pop up whenever the stack usage of a function goes beyond some limit you set - I think that setting it to 32k or 64k is a safe and sane default as e.g. macOS thread stack sizes are just 512kb
Re:Everything I wish I knew when learning C by LegionMammal978 on Monday November 28, 2022 @11:13PM (#33783609)
I don't think we're actually in disagreement here. It looks like I misread the parent comment to be claiming that fixed-size array assignment ought to be considered O(N), when no such claim is made.
Re:Everything I wish I knew when learning C by DSMan195276 on Tuesday November 29, 2022 @12:52AM (#33784137)
Yeah to clarify I'm definitely in agreement with you that it's O(1), the size is fixed so it's constant time. It's not like the 'n' has to be "sufficiently small" or something for it to be O(1), it just has to be constant :)

People are being very loose about what O(n) means so I attempted to clarify that a bit. Considering what assignments can already do in C it's somewhat irrelevant whether they think it's O(n) anyway, it doesn't actually make their point correct XD

Re:Everything I wish I knew when learning C by jcelerier on Monday November 28, 2022 @05:26PM (#33780749)
> IIRC C has an informal guarantee that no primitive syntax will ever cause the CPU to do more than O(1) work at runtime. Assignment is always O(1), and therefore assignment is limited to scalars.

this is absolutely and entirely wrong. You can assign a struct in C and the compiler will call memcpy when you do.

Enjoy: https://godbolt.org/z/98PnhYoev

Re:Everything I wish I knew when learning C by wnoise on Monday November 28, 2022 @05:35PM (#33780867)
And any structure is O(1), not O(n), because C structures are not parameterized.
Re:Everything I wish I knew when learning C by jcelerier on Monday November 28, 2022 @05:40PM (#33780918)
memcpy is not O(1)
Re:Everything I wish I knew when learning C by LegionMammal978 on Monday November 28, 2022 @06:03PM (#33781144)
It's O(1) relative to any size computed at runtime: that is, running the same program (with the same array size) on different inputs will always take the same of work for a given assignment.
Re:Everything I wish I knew when learning C by jcelerier on Monday November 28, 2022 @09:55PM (#33783131)
We're in the context of the assignment operation in the language here. Yes, in C you can only assign statically-known types but that does not mean you can just ignore that a = f(); may take a very different time depending on the types of a and f
Re:Everything I wish I knew when learning C by xigoi on Tuesday November 29, 2022 @12:56AM (#33784152)
> IIRC C has an informal guarantee that no primitive syntax will ever cause the CPU to do more than O(1) work at runtime.

How about CPUs that have no, say, division instruction, so it has to be emulated with a loop?

Re:Everything I wish I knew when learning C by naniwaduni on Tuesday November 29, 2022 @04:52PM (#33793871)
Fixed-width divisions are O(1), just comparatively expensive (and potentially optimized to run in variable time). Consider that you can do long division on pairs of numerals of, say, up to 20 digits and be Pretty Confident of an upper bound on how long it's going to take you (you know it's not going to take more than 20 rounds), even though it's going to take you longer to do that than it would for you to add them.
Re:Everything I wish I knew when learning C by pratk on Tuesday November 29, 2022 @01:32AM (#33784337)
Well C does allow "copying" an array if it's wrapped inside a struct, which does not make it O(1). gcc generates calls to memcpy in assembly for copying the array.