Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Foxfire_
Nov 8, 2010

The thing also leaves the file open if some errors happen and opens the file in (probably) the wrong mode.

The sensible thing is just to use gotos for the control flow instead of making a funnylooking goto out of do...while and break:

code:
image_t* img_load_from_filename(const char* filename)
{
    FILE* f = NULL;
    boolean success = FALSE;
    image_t* ret = NULL;

    const char* path = path_join(DATADIR, filename);
    if (path == NULL)
        goto exit;
    
    f = fopen(path, "rb");
    if (f == NULL)
       goto exit;

    image_header_t img_header;
    if (!img_read_header(&img_header, f))
       goto exit;

    ret = malloc(sizeof(image_t) + 8*img_header.data_size);
    if (ret == NULL)
        goto exit;

    if (!img_read (ret, f))
        goto exit;

    success = TRUE;
exit:
    if (f != NULL)
        fclose(f);
    
    if (!success)
    {
        free(ret);
        ret = NULL;
    }
    
    return ret;
}

Adbot
ADBOT LOVES YOU

Foxfire_
Nov 8, 2010

Suspicious Dish posted:

My favorite part is the segfault when one of the early conditionals fails. It's the little touches...

It looks technically correct (the best kind of correct) to me. The conditionals are required to short circuit out as soon as one is true, so the later ones never run.

Foxfire_
Nov 8, 2010

I'm guessing ported fortran linear algebra library.

Foxfire_
Nov 8, 2010

Juliachat: I'm on day 2 of porting/redesigning a program from Python to Julia! It's a video processing thing where you shove about 30GB of video in one end and descriptions of objects comes out the other.

Our reasons for switching were mostly driven by performance and python multiprocessing being a trainwreck. Julia added some inter-process queues in its last release that are good enough for easy IPC producer-consumer stuff and that's all we needed for synchronization. There's the start of a multithreading module, but it didn't have that many features last time I looked at it.

We did a bunch of Numba stuff in the python implementation, but it ended up being super annoying because you were basically always programming in the super striped down python numba supported, so in practice it was clunkier than even something like C++ (no vectors, no structs, no nested arrays, ...)

Foxfire_
Nov 8, 2010

Hydronium posted:

Found at work today: no code needed, the function name says it all. TrimAndAddSpaceAtEnd

Does it remove all the whitespace from the end of a string, and then add a single space at the end? Cause that's what it sounds like and that's a pretty good name if that's what it does.

Foxfire_
Nov 8, 2010

:eng101: C/C++'s slow build time is mostly due to the grammer being stupid, not the preprocessor being stupid.

code:
dick * butts;
Is this declaring a new variable named butts that's a pointer to the dick type or multiplying the variable dick by the variable butts? There's no way to tell without parsing everything else!

Foxfire_
Nov 8, 2010

Coffee Mugshot posted:

I'm a little confused because defining your own Boolean type isn't particularly a weird thing. That code snippet appears to be doing the weirdest type conversion I have ever seen. Without knowing what BOOL actually is (probably an integral value ), why can't the above code just do a simple type conversion from bool to BOOL? Knowing this is some C dialect, why wouldn't that function just take BOOLs as parameters in the first place so that implicit conversion could take over. Hell, even taking in a Boolean as a void* is a better approach than that snippet.

windows.h posted:

typedef int BOOL;
#define TRUE 1
#define FALSE 0

windows.h is older than stdbool.h, so it defined its own boolean type. It's still around because using the standard one is not worth breaking the API and ABI of just about everything in windows (sizeof(BOOL) != sizeof(bool), in theory or in practice)

That's a perfectly fine snippet since it's obvious what its doing.

Foxfire_
Nov 8, 2010

QuarkJets posted:

And my contention is that you shouldn't define DELAY_NANOSECONDS to be 5 billion, you should instead define DELAY_SECONDS to be 5 or at worst DELAY_MILLISECONDS to be 5000

Presumably the thing that takes the values wants nanoseconds. Doing unit conversions at every point of use (DELAY_SECONDS * NS_PER_S) solely to make a number that's hidden behind a macro smaller is dumb.

Foxfire_
Nov 8, 2010

Spatial posted:

Here's another fun C oddity.
code:
int x[10] = { 0 };

int y = 9[x];
int z = x[9];
int w = *(x + 9);
This code compiles and the three variables have the same value.

This still works in C++

z and w are things working totally normally. y is undefined behavior that will probably work on modern architectures.

Thou shalt not form any pointers that ever point to anything besides 0 or between the start of an array and one past its end, even if you never dereference them.

It'd crash on some old CPUs with dedicated base and offset registers (like things with a 16 bit memory space and 8 bit registers where pointers are done with register pairs).

Foxfire_
Nov 8, 2010

I was wrong about the ordering thing! Standard lets you put the pointer argument and integral argument in either order as long as there's exactly one of each.

Forming an invalid pointer is definetly undefined though.

C0x 6.5.6 posted:

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand.

If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.

In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)−N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist.

Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)−1 points to the last element of the array object.

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow;

otherwise, the behavior is undefined.

And from the rationale doc since that's hard to parse

C0x Rationale 6.5.6 1171 posted:

Any pointer arithmetic that takes a pointer outside of the pointed-to object (apart from the one past exception)
is undefined behavior. There is no requirement that the pointer be dereferenced; creating it within a
subexpression is sufficient.

It gives a Motorola 56000 as an example of a real processor still in use where invalid addresses will fault in a footnote.

Foxfire_
Nov 8, 2010

rjmccall posted:

lol no

Anyway, the restriction people keep quoting is specifically about pointer arithmetic, and it only prevents you from using pointer arithmetic to exceeds the bounds of an object (where those bounds include the one-past-the-end pointer), primarily as a way to allow the compiler to assume that subscripting into an array does not alias arbitrary other memory. It is not a general prohibition against forming or having a pointer that does not point at anything. It is of course undefined behavior to dereference a pointer that does not validly point to an object, outside of the specific exception for &*. The only general restriction on pointer values is that you cannot legally create a pointer that is less aligned than its pointee type; that is a rule that compilers are usually lax about until you actually use it to access the underlying memory.

But if you cast 7 to a pointer type, that is legal (assuming the pointee type is byte-aligned); and if there happens to be an object of that type at address 7, then it is legal to dereference the resulting pointer; and since compilers generally cannot know statically every possible valid address of an object, it has to let you get away with it. (But null is different.)

I was curious and found this in the section for conversions:

C0x 6.3.2.3 posted:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
Conversion of a null pointer to another pointer type yields a null pointer of that type.
Any two null pointers shall compare equal.
An integer may be converted to any pointer type.
Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

A compiler isn't allowed to refuse to compile char* a = (char*)5; and is supposed to document what it does, but doesn't have to do any particular thing.

Foxfire_
Nov 8, 2010

code:
int foo()
{
  int x = 0;
  return (x = 1) + (x = 2);
}
code:
def bar():
  x = []
  return x.append(1) + x.append(2)
Only real difference is that C doesn't specify an order to its + operator and Python does. :shrug:

Foxfire_
Nov 8, 2010

and that's what I get for writing examples while tired without running them

everybody pretend I wrote this instead please

code:
def foo():
  x = [1,2]
  return x.pop() - x.pop()

Foxfire_
Nov 8, 2010

I figured the target is more 'I am doing research on compiler/language design and am implementing something for a paper", not "I am writing production code"

So most of your work and bugs would be in compiler you're writing of in the input code you're feeding it. Debugging your compiler emitting bad Rust is probably easier than debugging it emitting bad LLVM or C and all you're really trying to show is that some basic concept is interesting/feasible.

Foxfire_
Nov 8, 2010

C# properties are nice for making noun-y things look noun-y.

Like if you have an Image class, Height, Width, NumPixels, BitDepth, NumBytes, and RowStride are all reasonable things to expose, and the implementation would probably have some of them be variables and some be calculated. Making them properties makes them all accessed the same and (in non-crap code) is strongly suggesting that accessing them is idempotent and inexpensive.

Foxfire_
Nov 8, 2010

Pollyanna posted:

Today I “fixed” a hanging CircleCI build by piping the offending command into cat. I do not know why it worked. All hail pipecat.

Whatever used to be connected to those pipes wasn't reading them.

Pipes are implemented with the OS maintaining a fixed size buffer that one process writes into and the other one reads from, along with some synchronization to keep track of what data has been written but not read yet. If the reading process stops reading, the buffer fills up and the writing one blocks waiting for buffer space to become available.

Foxfire_
Nov 8, 2010

Good Will Hrunting posted:

One of my PRs was just rejected because I named a boolean method "shouldOuputExtraFields" instead of "isOutputExtraFields" and when I said it was ugly and made no sense, the reasoning I got was "It may not seem grammatically unless you read it as "is the flag outputExtraFields set to true" which is fine." This is a configuration object being fed to another object upon instantiation and used to define behavior of the created object. I suspect the real problem is that it'll break another internal API and nobody wants to make the change.

I can't tell if we're supposed to make fun of you for misspelling output or not

Foxfire_
Nov 8, 2010

Bruegels Fuckbooks posted:

you can write all the old school c++ you want if you don't gently caress up and introduce memory leaks, oh wait, not going to happen.



(Also a totally valid use of C++ in lots of embedded environments)

Foxfire_
Nov 8, 2010

csv is probably the best long term storage format if you want a dataset to still be useable in 20 years.

HDF5 or a database will probably be long abandoned by then and their file formats are complicated and hard to reverse engineer from the data. You can go from unknown old datafile -> it's csv -> it's this particular flavor of csv -> here's a program that reads it fairly easily

Foxfire_
Nov 8, 2010

That is (A) bizarre and a coding horror in its own right, and (b) doesn't do what you want.

code:
void foo(const char& bar)
{
    std::cout << bar << std::endl;
}

int main()
{
    foo(*"hello");
}
prints 'h' not, 'hello' because bar is a single char.

Foxfire_
Nov 8, 2010

Does reading it go across a bus that is also being used for other things (DMA) so that spinning on it will block stuff?

Foxfire_
Nov 8, 2010

Things volatile does:

- The variable must be given an address. The compiler can't just use a register
- Any load or store must actually happen. The compiler can't omit them even if no write happened since the last time it read it, it's writing the same value twice, or if it can determine that no other computation depends on the load/store.
- The compiler must issue loads/stores in the same order relative to every other volatile load/store. No swapping the order of them to make things faster

Things volatile doesn't do:

- Stop the processor from reordering loads/stores. A fancy ARM can and will do this unless you tell it when it's not allowed to
- Impose any ordering from the point of view of another core. Other cores can see the same memory accesses happen in different orders from the initiating core, and in different orders from each other.
- Do any sort of cache coherency operations. A volatile store will happily repeatedly rewrite the same data in cache and never actually go to memory.

It's a compiler-only thing. It limits how the compiler can rearrange and optimize, but has no impact whatsoever on the hardware rearranging and optimizing.

Foxfire_
Nov 8, 2010

Seems fine. It's not actually about deprecating volatile, just the insane person stuff that's technically allowed:

code:
volatile int WhatDoesThisEvenMean(volatile int x)
{
  return x++;
}

Foxfire_
Nov 8, 2010

JawnV6 posted:

Oh, right, I learned something: Herb Sutter is also a fan of the Kingkiller series, and was on the review for this. So the cringe-inducing parts were for someone.

tbh I never considered some of the corner cases around incrementing, in the i-dont-care-if-this-tears variety, but still think there should be some way to specify "please spin on this BS operation that you know is BS for Reasons"

There's a part where it says casting between normal and volatile pointers should still be allowed because important existing code (linux) does that all the time.

So you could still spin with
code:
int spin = 10000;
volatile int* volatileSpin = (volatile int*)&spin;
while (*volatileSpin > 0)
{
  *volatileSpin = *volatileSpin - 1;
}
even if you can't make stack variables volatile

Foxfire_
Nov 8, 2010

"ASCII text over serial" is a fairly common protocol for talking to equipment from embedded stuff that adds string handling to things.

I like to do strings as unterminated fixed size arrays in structs i.e.
code:
struct ThingCmd
{
    char Text[THING_CMD_SIZE];
};
You can copy them with =, sizeof() them, static analyzers are better about noticing if you overrun them, and they tend to explode dramatically if someone isn't paying enough attention and tries to use str* functions on them.

Foxfire_
Nov 8, 2010

Votlook posted:

I once heard a system administrator say "Does that /dev/null directory even exist?" while inspecting a bash script we delivered.
Supposedly this was their top guy for Linux.

:thejoke:?

Foxfire_
Nov 8, 2010

:can:/CAN

The thing car manufacturer's are trying to avoid is having to physically segregate the bus so they only have to route one cable. Unidirectional network things only even make sense when there are two buses and you are limiting what can be copied from one to another.

The situation you want to avoid is a subverted entertainment unit being able to say "Engine RPM: 100000!" and everyone else listening. You could do that with two buses linked by a widget that knows what IDs belong on each side, but you'd have to run two physical cables ($) and that widget would probably have to be semi-custom (it can't just do an echoing thing because of the electrical arbitration)

Foxfire_
Nov 8, 2010

iospace posted:

There were a couple ways, not sure how much of it was involving proprietary code but you could do it pretty much the same way you introduce a segfault in other situations: try to access poo poo you have no access to.

:confused: in x86 real mode don't you have access to everything because there is no MMU/the MMU is disabled? Do you mean bus error (CPU tried to do the access and no other chip acknowledged a read/write to that address)?

Foxfire_
Nov 8, 2010

10x engineers flip the electrons with their minds. You can find them by looking to see if they have a keyboard plugged in.

Foxfire_
Nov 8, 2010

Python3's unicode/bytes filenaming problems aren't python specific; they're mostly fallout from trying to be cross platform and complete in a universe where unix filenames are alien unicorns compared to how they work on windows/macs/sane people's brains.

A filename on unix is not text. It is an arbitrary sequence of any bytes except for 0x00 [reserved for terminator] and [0x2F reserved for separating directories].

Things that are perfectly fine unix filenames:
- Byte sequences that don't decode into valid UTF-8 (e.g. 0x80, 0x01 isn't the right number of bytes to form a UTF-8 codepoint, but it's a legal filename)
- Byte sequences that don't decode into printable ASCII (e.g. "<newline>, <bell>, <bell>, <backspace>, <linefeed>" is a legal filename)
- Byte sequences that decode into shell bombs (try doing 'rm *' in a directory that contains a file named '-rf /' for fun and profit!)

Anything that renders a filename typically either assumes an encoding or takes it from a system-wide setting. But two systems won't necessarily agree about how to display any particular filename (if it is displayable at all).

Python needs the bytes interfaces since you don't want it to explode when it gets a non-unicodable filename, and if it's going to be a useful scripting language you don't want it to be unable to manipulate some files, but people also want to treat filenames as text, since 99.999% of the time they are and that's how people actually think of them.

Foxfire_
Nov 8, 2010

I'm not super familiar with APFS, so I did some googling and apparently they fixed it's initially stupid behavior.

Now it stores utf-8, preserving the input normalization, but uses a normalization insensitive comparison for locating files. (This is stolen from what ZFS) does.

This seems like the least insane thing possible. It doesn't support distinct files created on some other filesystem named with the same Unicode text in different normalizations, but anyone who tries that deserves what they get.

Posix technically only requires filenames to support Roman alphanumeric+some common symbols, so it's still compliant, just not what unixes have traditionally done

(also, I was wrong and windows is also bad. It's paths are arbitrary sequences of int16s, they don't need to be valid utf-16, and the same text encoded differently isn't the same path)

Foxfire_
Nov 8, 2010

Soricidus posted:

Can you name anything that isn’t?

A rat's anus?

Foxfire_
Nov 8, 2010

ultrafilter posted:

Math keeps changing

JavaScript math is even more of a horror than the rest of the language.

Getting an exact particular float from an complicated math operation implemented in a library is not a reasonable expectation. Floating point values are not real numbers and if you're implementing numerical code, you need to deal with that. (Especially since the value he's looking for is not the closest double to the correct one: he expects gamma(11.54)=13098426.039156161 and the actual closest one is ~13098426.039075902)

Foxfire_
Nov 8, 2010

Captain Cappy posted:

I've written bool ? true : false before, when I wanted the thing to be 1/0 and not a random int someone assigned to the bool (thanks C). Although the promove is !!bool, probably.

Jabor posted:

This doesn't necessarily work - if you have a bool that doesn't hold a legal bool value, and you try to read it as a bool, you're in undefined behaviourland. The compiler, as always, is allowed to assume that your code does not have any undefined behaviour, and just optimize away your checks.

C99 bool aka _Bool normalizes to 0/1 automatically when assigned to (unless your accessing it via a char* alias for some reason).

Foxfire_
Nov 8, 2010

The only uses I can come up with is panicky crash handler or some bizzaro chip that needs to busy loop while waiting for an interrupt. Everywhere else you'd access a register (volatile reads or writes count as side effects)

Foxfire_
Nov 8, 2010

Guess what language uses the same words for more than one concept!

That's about operation sequencing. It splits expressions into value computation and side effect, then has rules for what order they happen in.

i.e. how to interpret an expression like
code:
*(somePointer[*someOtherPointer*2]) = *(someOtherPointer++ * 3);
http://eel.is/c++draft/intro.execution


The infinite loop part is more explicit:

C++ draft posted:

The implementation may assume that any thread will eventually do one of the following:
(1.1) terminate,
(1.2) make a call to a library I/O function,
(1.3) perform an access through a volatile glvalue, or
(1.4) perform a synchronization operation or an atomic operation.
[ Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. — end note ]
http://eel.is/c++draft/intro.progress

Foxfire_ fucked around with this message at 08:59 on Mar 12, 2020

Foxfire_
Nov 8, 2010

It does look OOP though? It's not using syntax to make life easier, but there are conceptual Team and Player objects owning data and operations (assuming there's more functions that were omitted), just accessed with an explicit this parameter instead of implicit.

(Assuming that is a index into a global table instead of wrangling with custom allocators)

It's not good syntax, but it's not a design horror at least.

Foxfire_
Nov 8, 2010

Absurd Alhazred posted:

Why are you assuming the opposite of what the poster wrote?

I'm making assumptions about what's inside the ... in the Team class (presumably more static functions that manipulate Team objects)

OOP is a design pattern, not any particular syntax. You can do it in languages with no explicit syntax support for it or do it in C++ without using member functions. It's clunkier and more verbose, but it has the same organizational advantages/disadvantages.

The classic C version would be like:
code:
struct SomeClass
{
    int aPrivateMemberVariable;
};

void SomeClass_Constructor(SomeClass* this);
void SomeClass_AMemberFunction(SomeClass* this, int aParameter);
int SomeClass_GetFoo(const SomeClass* this);
void SomeClass_Destructor(SomeClass* this);
and then relying on callers to (1) not directly access the variables in the struct, (2) explicitly call constructor/destructor functions.

The posted code looks like basically that, except using indices into a global table instead of something typesafe (which is bad!). It sounds like the original change request was kind of dumb and whoever got stuck with it wanted to satisfy a manager and move on, which seems reasonable to me (especially since the alternative would be to fight C++ allocator syntax to still use the globally allocated tables)

Foxfire_
Nov 8, 2010

Some notifications are good. I like notification+sound for "you have a meeting in 10mins" and "someone is trying to get your attention in work chat" on my work laptop.

Adbot
ADBOT LOVES YOU

Foxfire_
Nov 8, 2010

VikingofRock posted:

It's easy to fill an array with numbers; the hard part is figuring out which numbers to fill it with.

Well look at this fancy-pants 100x engineer

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply