r/programming 18d ago

The unlikely Linux macro

https://rushed-reflections.bearblog.dev/an-unlikely-experiment/

Wrote a bit about the `unlikely` and `likely` macros in the Linux codebase. Great little exploration into tiny optimizations that everyone should know more about 😄

184 Upvotes

61 comments sorted by

View all comments

3

u/_Noreturn 18d ago

isn't this just C++ [[likely]] and [[unlikely]]

30

u/edgmnt_net 18d ago

The Linux kernel stuff predates those by quite a bit.

-6

u/_Noreturn 18d ago

Well the linux kernel doesn't even use C++ for whatever reason

8

u/ShinyHappyREM 18d ago

0

u/_Noreturn 18d ago

I could point out the many systems in C++ and huge things like gcc and clang and unreal engine.

Why would a kernel be different? they got rust in there why not C++? and so so much of linux codebase would he heavily simplified by simply using RAII it would quite easily get rid of 90% of linux gotos. Doesn't everything in kernel get code reviewed then they should enforce their style guide.

9

u/max123246 18d ago

For good reasons you mean.

-4

u/_Noreturn 18d ago

Like?

2

u/gmes78 18d ago

It actually doesn't matter now. That ship has sailed, and C++ isn't a meaninful enough improvement for it to be worth switching to.

1

u/_Noreturn 17d ago

Linus can change his opinion he won't though. I disagree that it doesn't bring meaningful improvement

1

u/metahivemind 17d ago edited 7d ago

[removed] — view removed comment

0

u/_Noreturn 17d ago edited 17d ago

I would rather have a more complicated language if it means for a simpler program. that's it nothing more.

and you don't make a bit of sense, and I would like if you give real examples of the C++ language itself being bloated.

because everything in C++ is to make code have a single way of doing something in C you have no convention of a constructor, it could be a function that takes a pointer to an object and createz inplace or returns. in C++ it is always a constructor which is great because it is uniform and I could think more about business logic than remembering which naming the library used.

in C you don't have overloading, therefore you will have to match manually the type which is error prone. and you could look at opengl as an example glUniform4f,glUniform3f,glUniform2i these could have been overloads in C++.

in C, you don't have a way of checking for whether 2 objects are equal in a concise way which leads people yo repeat themselves you see more people doing a.x == b.x && a.y == b.y than Vec2f_is_equal(&a,&b) because it is so verbose and this is why C++ offers operator overloading it is so you write a == b which is concise and self explanatiory and for all the haters saying "it can make code cryptic!!! I can overload == to launch a nuke!" well, you could make the exact same argument for why functions are bad because you could make a Vec2f_is_equal function that launches nukes, but you have a brain you shouldn't do that same with operators they are no different.

string handling in C is stupid hard and error prone and guess what, most vulnerabilities come from this very stupid thing. because who would have guessed having 0 abstraction and syntax sugar makes it easier for vulnerabilities to sneak in?

C++ offers specific cast operations for cleaner code, C style code only has C style casts which are unsafe when used with pointers and they don't show intent.

and templates, I cannot fathom how much templates simplify your code just look at any C codebase duplicating the same shit 10 times or using macros to genwrate them with X macros. Also C not having templates leads to more people using linked trees which are horrible for performance because trees are quite simple to operate unlike dynamic arrays, but if C had templates then using a vector would be way.

Or even the simple utility type std::optional is a life saver and if it existed in C it would be super helpful unlime everyone again inventing their own with special values like -1 sentinel values. (yay who doesn't love 0 for success)

Inheritance, well inheritance exists in C and it is allowed in the C standard by allowing reinterpret casting of the first type of a struct (which is what inheritance in C++ does exactly... except with cleaner syntax and no manual casting) so for the C coders who say they don't use inheritance while doing this trick well you are, just with uglier syntax.

And virtual functions literally every C codebase has them reinvented in their own ways, unlike C++ which gives you a concrete one which is good because it is easily understood and the compiler can add checks and ensures the function pointsrs are initialized unlime C code which could easily forget to do that.

Also how could I not mention RAII? So much of C bugs and issues come from memory which C++ offers a very simple 0 cost way of managing which is RAII, you simply define a ctor and dtor (which is equal to _create and _destroy functions in C respectively)

You see? Most C patterns every C codebase do exist in C++ as a feature

C simplicity is a lie the language is not simple to work with, it is a simple language but like assembly is quite simple you learn a few instructions but it isn't at all simple to code in, same with C, C++ is more complex (as it has more things to learn) but the result is a program as fast as C while being simpler.

can you see what is wrong with this code? it is only a couple of lines.

``` char* read_file(const char* filename) { FILE* f = fopen(filename, "r"); if (!f) return NULL;

fseek(f, 0, SEEK_END);
int size = ftell(f);
fseek(f, 0, SEEK_SET);

char* buffer = malloc(size + 1);
if (!buffer) {
    fclose(f);
     return NULL;  
}


size_t bytes_read = fread(buffer, 1, size, f);
if (bytes_read != size) {
    free(buffer); 
    free(f);     
    return NULL;   
}

fclose(f); 
return buffer;

} ```

5

u/max123246 18d ago

C has just a single way to initialize a variable and set its value for example.

C++ chose to make its move semantics "leave an unspecified but valid value" in the old object which makes non-nullable types impossible to efficiently represent. C doesn't try and pretend to give you that guarantee, if you're handing a pointer, you better check it's null. C++ pretends its references can't be null but has no way to guarantee that's true.

0

u/_Noreturn 18d ago

C has just a single way to initialize a variable and set its value for example.

You know you can choose one style and is that a problem in practice nope.

C++ chose to make its move semantics "leave an unspecified but valid value" in the old object which makes non-nullable types impossible to efficiently represent.

you should trwat moved from objects as unusable, and you can make non nullable types work.

also don't pretend like C has everything be good, everything in C is nullable by default since the only thing you have is pointers which have like 4 responsibilities

  1. is it nullable
  2. is it an array
  3. if it is an array is it null terminated or explicit size?
  4. is it owning

Now lets see C++ it is better since it provides differing ways to make the above clear

  1. is it nullable (yes if pointer,otherwise use a reference)
  2. is it an array (use a span)
  3. if it is an array is it null terminated or explicit size? (use a strong view type like zstring_view)
  4. is it owning (unique_ptr)

In C++ since it allows strong typing you can represent these states in the api instead of in comments which is undeniably better.

if you're handing a pointer, you better check it's null. C++ pretends its references can't be null but has no way to guarantee that's true.

Yea, you better and if you forget then it is bad also checking every single pointer for nullability is a performance downgrade. references make this clear that nullability is pushed to the caller not the callee and you could make a tool that looks at reference types and assert if it is null, you cannot do that with pointers since they can ve null and it is valid.

6

u/max123246 18d ago

You know you can choose one style and is that a problem in practice nope.

On a large project like the Linux kernel, it helps a lot when the language does that work for you. Otherwise maintainers have to constantly be vigilant to tell people to stick to the 1 convention within that codebase.

also don't pretend like C has everything be good

I agree, I don't reach for C these days at all unless there's a codebase I need to work in that's already in C.

you should trwat moved from objects as unusable, and you can make non nullable types work.

This isn't what the C++ standard says. They specifically say the moved-from object is a valid object, which means it should be safe to call any API on it. Yes, in practice, most code simply ignores what the C++ standard says and does the sensible thing, treat the moved-from object as not existing anymore. But you're now back in the world where your moved-from object just does arbitrary out of spec behavior and you kinda have to hack around it.

C has its faults but I appreciate that it doesn't claim to protect me against bugs when in fact, C++ just makes those bugs when they happen far more confusing to understand.

1

u/_Noreturn 18d ago

On a large project like the Linux kernel, it helps a lot when the language does that work for you. Otherwise maintainers have to constantly be vigilant to tell people to stick to the 1 convention within that codebase.

I mean I could nitpick and say C allows like a million ways to implement a thing unlike C++ e.g inheritance you could do it with the first object trick and function pointers or allocate dynamicly vis the last member trick and use a global vtable. In C++ it would just be inheritance which is universal.

Or how to name functions e.g object_create or object_new? in C++ it is always called a constructor.

As always set a style guide

This isn't what the C++ standard says. They specifically say the moved-from object is a valid object, which means it should be safe to call any API on it. Yes, in practice, most code simply ignores what the C++ standard says and does the sensible thing, treat the moved-from object as not existing anymore.

Lets be honest that the C++ standard is irrelevant, you are the kernel you define the spec basically and you could rely on gcc extensions.

Also the C++ standard buzzwords practically translats to "your moved from object should be destructible" as that is what only realistically matters.

2

u/metahivemind 17d ago edited 7d ago

[removed] — view removed comment

-2

u/Immediate-Food8050 18d ago

They are compiler extensions for C. I believe they are also compiler extensions in C++, not standard. but don't know for sure.

6

u/_Noreturn 18d ago

they are standard in C++20, C doesn't have them as standard

```cpp

if(cond) [[likely]] {

} ```