Live data from Hacker News

Tell HN: C Experts Panel – Ask us anything about C

news.ycombinator.com

911–920 of 978 posts

Re: Tell HN: C Experts Panel – Ask us anything about C

#911
post #184

A lot C programmers prefer to keep structures within the C source file ("module"), as a poor man's encapsulation. For example: component.h: struct obj; typedef struct obj obj_t; obj_t *obj_create(void); // .. the rest of the API component.c: struct obj { int status; // .. whatever else }; obj_t * obj_create(void) { return calloc(1, sizeof(obj_t)); } However, as the component grows in complexity, it often becomes nece…

There are already "Name Spaces" in C and modules are actually object files or libraries.

You can spread components in as many object files or libraries as you wish.

IMHO it's not a C related problem but a code design one.

Write libraries (with headers) only if you need to share the code but if you're not sure about that just include it for your specific program.

There is no shame to include local files containing declarations and definitions.

I think it is a misconception from C programmers to write headers for local purpose.

Re: Tell HN: C Experts Panel – Ask us anything about C

#912
post #729

Earlier quoted context omitted.

C currently replaces my use of an array with a pointer. This sucks, because I'd have taken the address if I wanted that. Your proposal replaces my use of an array with two things, a pointer (as before) and a length. This is not too helpful, because I already could have done that if I'd wanted to. What is missing is the ability to pass an array. Sometimes I want to toss a few megabytes on the stack. Don't stop me. I s…

> Your proposal replaces my use of an array with two things, a pointer (as before) and a length. This is not too helpful, because I already could have done that if I'd wanted to. C doesn't have a reasonable way of doing that. I know my proposal works, because we've been using it in D for 20 years.

Your proposal does not work, at least when making the declarations binary compatible with older code.

Note that C is a pass-by-value language, so passing an array means that the called function can modify the content without the modifications being seen in the caller.

To sort of pass arrays in an ABI-compatible way, the version for older code would require putting the array inside a struct.

Even that doesn't fully work with any ABI that I've ever heard of. The struct doesn't really get passed. Disassemble the code if you have doubts. The caller allocates space for the struct, copies the struct there, and then passes a pointer to the struct. From the high-level view of the language, this is passing the struct, but the low level details are actually wrong.

Re: Tell HN: C Experts Panel – Ask us anything about C

#913

Earlier quoted context omitted.

No enforcing! This is useful even when it's, strictly speaking, a lie. Suppose I want to add some debug tracing into f(): f.c: 42: f entered f:c: 43: returning 2 that's a side effect, right? But now the pure attribute tells a lie. Never mind though; I don't care that some calls to f are "wrongly" optimized away; I want the tracing for the ones that aren't. In C++ there are similar situations involving temporary objec…

Such attributes would be most useful if the semantics were that any time after a program receives inputs that would cause a "pure" function to be called with certain arguments, a compiler may at its leisure call the function with those arguments as many or as few times as it sees fit. The notion that "Undefined Behavior" is good for optimization is misguided and dangerous. What is good for optimization is having sema…

> flatfinger

https://news.ycombinator.com/user?id=supercat

?

If you contact the HN gods maybe there is a way to recover access to that account.

Re: Tell HN: C Experts Panel – Ask us anything about C

#914

Earlier quoted context omitted.

I'm not disagreeing, just showing code to illustrate why memcpy doesn't work for this. Although I do disagree that writing a signed value is useful - you can eliminate 18 of those variations with a single intmax_t-to-twos-complement-uintmax_t function (if you drop undefined behaviour for (unsigned foo_t)some_signed_foo this becomes a no-op). A set of sext_uintN functions would also eliminate 18 read-signed versions.…

> Although I do disagree that writing a signed value is useful Although the Standard defines the behavior of signed-to-unsigned conversion in a way that would yield the same bit pattern as a two's-complement signed number, some compilers will issue warnings if a signed value is implicitly coerced to unsigned. Adding the extra 18 forms would generally require nothing more than defining an extra 24 macros, which seems…

Fair point; even if the combinatorical nature of it is superficially alarming, that's probably not a productive area to worry about feature creep in.

Re: Tell HN: C Experts Panel – Ask us anything about C

#915

Earlier quoted context omitted.

> Explain just how malloc() and free() work under the covers and the implications for multi-threading, memory leaks, virtual memory paging, etc. > > Maybe also cover some means, algorithms, and code for reporting on the state, status, etc. of the memory use by malloc() and free(). Strictly speaking, these are implementation details that the C standard leaves unspecified. If you want to know how the memory allocation…

Thanks. > Did you have more specific questions in mind? On stack overflow, my understanding was that could encounter that fatal condition from suddenly a too deep call stack , that is, too many calls without a return. So, if the "stack" is a, say, finite resource, then the programmer should know in the code how much of that resource is being used and act accordingly. For a preprocessor for C++, I IIRC at one point th…

> So, if the "stack" is a, say, finite resource, then the programmer should know in the code how much of that resource is being used and act accordingly.

And this is true, but IIRC statically determining stack bounds for arbitrary programs is not an easy problem to solve, especially if you call into opaque third-party libraries.

> For a preprocessor for C++, I IIRC at one point the definition of C++ was in terms of a preprocessor

I wouldn't know about defining C++ in terms of transformations to C, and searching for that is more difficult. I would guess that the abandonment of the preprocessor approach to compilation would also have meant the abandonment of defining C++ in terms of C, especially once C++ really started picking up features.

> The issue is that at least at one time it seemed difficult to be precise about C++ semantics, that is, what the code would do and how it would do it. Maybe now C++ is beautifully documented.

C++ has had a formal specification since 1998, which might count as documentation for you.

Re: Tell HN: C Experts Panel – Ask us anything about C

#916

Earlier quoted context omitted.

What are the advantages of saving the end as a pointer? Genuinely curious. Seems like a length allows the end pointer to be quickly calculated (data + len), while being more useful for comparisons, etc.

You can remove the first k elements of a view with data += k. With the length you would need to do data += k; length -= k Especially if you want to use it as safe iterator, you can do data++ in a loop

Got it. That is really neat, going to add to my bag of tricks...

Re: Tell HN: C Experts Panel – Ask us anything about C

#917
post #336

Earlier quoted context omitted.

Have you considered adding intrinsic functions for arithmetic operations that _do_ have defined behavior on overflow. Such as the overflowing_* functions in rust?

The semantics most programs need for overflow are to ensure that (1) overflow does not have intolerable side effects beyond yielding a likely-meaningless value, and (2) some programs may need to know whether an overflow might have produced an observably-arithmetically-incorrect result. A smart compiler for a well-designed language should in many cases be able to meet these requirements much more efficiently than it c…

oops, i meant the wrapping_* functions

Re: Tell HN: C Experts Panel – Ask us anything about C

#918
post #884

Earlier quoted context omitted.

Same here. But I instead run a loop over a range around MAX_INT (or wherever the issue is) and print the result, so I know I'm doing what I think I'm doing. Exhaustive testing is quick, with a computer!

This isn't a good idea either: if you're dealing with undefined behavior the way the complier translates your code can change from version to version, so you could end up with a code that works with the current version of GCC but doesn't work on the next. Personally I don't agree with the way GCC and other comipers deal with UB, but this would be off topic.

Hm. May be off-topic by now. Incrementing an int is going to work the same on the same hardware, forever. Nothing the compile has any say in.

Re: Tell HN: C Experts Panel – Ask us anything about C

#919
Rather than trying to come up with "compromise aliasing rules", the Standard needs to recognize that different tasks require different features, and allowing all possible optimization opportunities that would be useful for some tasks would make an implementation totally unsuitable for others.

I would suggest that the Standard define directives to demand three modes, with the proviso that a compiler may reject code which demands a mode it cannot accommodate:

1. clang/gcc mode, which would be adjusted to match the way clang and gcc actually behave, as well as anything they want to do but their interpretation of the Standard woudln't allow.

2. precise mode, which behaves as though all loads and stores of objects whose address are taken behave according to a precise memory-based abstraction

3. sequence-based mode, which would allow compilers to hoist, defer, consolidate, and eliminate loads and stores in cases where they honor data dependencies that are visible in the code sequence, but would require that compilers recognize visible dependencies which clang and gcc presently ignore, and would also require that the definition of "based on" used by "restrict" recognize that any pointer formed by adding or subtracting an integer from another pointer by recognized as "at least potentially based on" the former, even in corner cases where clang and gcc would ignore that.

Recognizing mode #1 would avoid allow clang and gcc to keep using their aliasing logic with programs that can tolerate it. Mode #2 would ensure that all programs that have trouble with that logic could have defined behavior by adding a directive demanding it. Mode #3 would allow most of the same useful optimizations as mode #1, but work with a wide range of programs that would presently require `-fno-strict-aliasing`.

If one recognizes the need for different modes, the effort required to describe all three modes would be tractable, compared to the obviously-intractable problem of reaching consensus about how one mode that would need to serve all purposes.

Re: Tell HN: C Experts Panel – Ask us anything about C

#920

Earlier quoted context omitted.

The problem is that under modern interpretation, even if some parts of the Standard and a platform's documentation would define the behavior of some action, the fact that some part of the Standard would regards an overlapping category of constructs as invoking UB overrides everything else.

I could imagine misguided readings of some coding standard advice that would lead to that interpretation, but it's still not an interpretation that makes sense to me. Implementations define undefined behavior all the time and users rely on it. For instance, POSIX defines that you can convert an object pointer into a function pointer (for dlsym to work), or implementations often rely on offsets from a null pointer for…

Such an interpretation would be the only way to justify the way the maintainers of clang and gcc actually behave in response to complaints about their compilers' "optimizations".
Post reply on HN