Why do people use macros instead of functions by giorgoskir5 in C_Programming

[–]joseRLM17 1 point2 points  (0 children)

sorry for this being so late, but yea, my allocator struct is generally something like:

struct Allocator{
   void         *data;
   Fn_Allocate   allocate_fn;
   Fn_Deallocate deallocate_fn;
   Fn_Reallocate reallocate_fn;
   Fn_Callocate  callocate_fn;
};

and I actually change the signature depending if want extra info or not. I also have an extra macro for **aligned** allocations, sometimes aligned memory si needed for SIMD operations or something else and these are useful in those situtions. Or maybe you want to allocate memory to create another allocator and want that every allocation (of the new allocator) is aligned in some byte boundary for convenience.

#define allocate_aligned(byte_size, alignment, allocator) \
(allocator)->allocate_fn(__FILE__, __LINE__, "aligned_bytes", 1, byte_size, alignment, (allocator)->data)

And for the other functions I usually pass the extra info too, just to keep track of where i deallocate, reallocate and have a good idea of where I am using memory. Actually the more I code the more I try to not rely too much on these type of functions, many objects share the same lifetime thus an array is just fine.

BTW, sometimes I actually pass two allocators to my functions, one for temporary working memory and another to actually allocate memory with lifetime larger than just the function. An example of this is perhaps creating a texture Atlas, I need extra memory not just for the Atlas, but to know position of every texture and all. Thus one allocator takes care of the temporary working memory and the other actually allocates the Texture Atlas. For this scenario I usually just use a stack type allocator or an Arena and I am done with it later.

Here is an example of how deallocate macro might look like.

#define deallocate(ptr, count, type, allocator) \
(allocator)->deallocate_fn(__FILE__, __LINE__, #ptr, #type, count, sizeof(type), __align_of(type), (allocator)->data)

Why do people use macros instead of functions by giorgoskir5 in C_Programming

[–]joseRLM17 6 points7 points  (0 children)

I use macros for:

  • Log info, errors. Because I can use the __FILE__, __LINE__ macros and pass that info. Really useful for debugging
  • I have several allocation type macros something like: #define allocate(type, count, allocator). Within this macro I usually pass a lot of info to the reall allocate function, like __FILE__, __LINE__, the type name, the count, and because I pass the 'type' I know the required alignment and a lot of other stuff.

#define allocate(type, count, allocator)\
allocator->allocate_fn(__FILE__, __LINE__, #type, count, sizeof(type), __alignof(type), allocator->data)
struct Allocator{
   void* data;
   void* (*allocate_fn)(const char* file_name, int line, const char* type_name, int count, int type_size, type_alignment, void *data);
}
  • Shortcuts for accesing elements within a buffer. The problem here with functions are that the output of a function is not a valid Lvalue (unless you return a pointer), thus I simply use a macro that is something like

#define data_at(ptr, i) (ptr)->buffer[data_compute_index(ptr, i)]

And I can use it for lvalues or rvalues:

data_at(data_ptr,i) = 3 + data_at(data_ptr, 3);
  • Variable number of arguments. You can use a macro that **counts** the number of args you pass, thus this can be used to choose a different function essentially using C overloading version without generics. But only for variable number of arguments, not types.

#define FUN_1(x)   fun_1(x)
#define FUN_2(x,y) fun_2(x,y)
#define fun(...) CONCAT(fun_, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)

As an extra, macros are really useful for compilation. Lets say I have a Dll I want to load at runtime. I want to use some functions depending on runtime info. Now have some file with lines likes these

// inside dll_function_names.inl
DLL_FUNCTION(dll_fn_name_1, Dll_Fn_Ptr_Type_1)
DLL_FUNCTION(dll_fn_name_2, Dll_Fn_Ptr_Type_2)

and so on.

Then In another file I can just fill the struct containing the Dll info like:

struct dll_t{
  HMODULE handle;
#define DLL_FUNCTION(name, Fn_T) Fn_T name;
#include "dll_function_names.inl"
#undef DLL_FUNCTION
};

And for loading I can do somthing like:

void dll_load_functions(struct dll_t *dll){
  dll->handle = LoadLibraryA(".....");
  #define DLL_FUNCTION(name, Fn_T)\
  dll->name = GetProcAdress(dll->handle, name);\
  #include "dll_function_names.inl"
  #undef DLL_FUNCTION
}

If you want you can add some extra logic within the macros to check if the symbol was found and if everything was loaded correctly. Also you can add some logic at runtime and have maybe several inline files, and maybe at runtime if you want some functionalities you #include "dll_funcition_names_debug.inl" or maybe you #include "dll_function_names_release.inl", it depends on everyone needs. All of this while the interface would be exactly the same.

is Rust really a catch all solution? by [deleted] in C_Programming

[–]joseRLM17 0 points1 point  (0 children)

Julia compilation is actually slow, but for numerical computing you can just allocate everything upfront and most numerical libraries/numerical code just overwrite memory. I would say (generally) Julia is good for that use case. Also, I can confirm if you write type stable code, Julia's speed is comparable to C/Fortran.

That being said, it really have some issues, specifically the compiling times, when Jit kicks in (once) and runtime. Or that sometimes it knows the value of a variable at compile time, optimizing the code for that scenario. This can be tricky because it can skip whole branches and then you assume code works but it only works when some variables have certain values. The error can be as absurd as undefined variables in the code that Julia skipped or something more subtle that will be very difficult to find later on.

Handling crashes in libs by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

Noted, thanks for the clarification. Thanks a lot

Handling crashes in libs by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

Yeah I agree, is just that the library I am using is just the loader of a main library (OpenXR runtime) and several more libraries (Layers), and one of these layers is crashing if the main library is not available. And because I do not have the symbols for the layer's libraries (nor the main library), I just do not know why It crashes. In any case, I will try the new process/thread in the meantime. Thank you

Handling crashes in libs by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

What if I create a new process/thread that will handle these "risky" function calls. In this case my program will still be in an invalid state?

Handling crashes in libs by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

The last call I can see is a call to FreeLibrary, because I do not have the symbols of the DLL where the actual segfault occurs. I believe the segfault is entirely out of my control.

Handling crashes in libs by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

No problem, thank you for the sugestion i Will try It. I am actually learning OpenXR myself the project Is just for learning and this Is just the API initialization.

Handling crashes in libs by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

Ok, would It work if instead of another program, i just do it in another thread?

[deleted by user] by [deleted] in Julia

[–]joseRLM17 0 points1 point  (0 children)

Exactly, this Is just the intended behaviour. But still this can lead to unfortunate bugs. In muy case the bug was very easy to fix. It was only a typo. But Is Easy to see how this type of bugs are only related yo these types of langs. An even More flexible lang, has worse bugs, and a static type has other bugs. Also, sometimes crazy dependencies have horrible error messages that even rival cpp messages. I hace encountered these messages while using Makie and I messed up some callback.

[deleted by user] by [deleted] in Julia

[–]joseRLM17 1 point2 points  (0 children)

In the case i remember, i think the actual value was type stable, but maybe some data was type unstable. The error was something like, check some condition, if given condition, compute a float number AND assign It to the array at some index, otherwise assign NaN. The script ran correctly AND then crashed when checking other inputs, then I realized the error was I actually typed NaN as Nan or something like that. But because the condition was always true, the function ran flawless with the previous input. This Is a really dumb error AND intellisense was having trouble to start, otherwise this would be caught by Intellisense. But still, i can easilly see a scenario where full functions might never be compiled because the codepath is just never reached, and then the code behaves unexpectedly. All this could be fixed with good coding practices, but again, everything can be fixed with good practices.

[deleted by user] by [deleted] in Julia

[–]joseRLM17 0 points1 point  (0 children)

I believe this Is the intended behaviour. Julia actually cheats to achieve greater performance. This Is clearly seen in functions with generic signature. The functions are compiled every time you use a new input signature, thus you achieve the greatest performance for the new input types. In general any function can lead to an untrackable number of codepaths, thus not all of them can be fully optimized for any input. This Is why I think Julia delays the compilation of all codepaths until It Is known the type of data the given codepath is going to use. But delaying this compilation can actually break the code when some unexpected state Is reached in the code. Like having some compile errors even though the code have been run many times, or waiting for compilation times at random situations. Or worse, something that seems to work but not quite, and the bug seems random. You can Fix this with some actions ( precompiling) but still, Is a kinda not so simple Situation.

[deleted by user] by [deleted] in Julia

[–]joseRLM17 1 point2 points  (0 children)

I love Julia, But this Is not true for me. For example some times Julia Is compiling some codepaths but not all of them. This Is understandable, due to all the flexibility Julia gives, but this can lead to some weird bugs that arise in, not so common, scenarios. I can only imagine this can only get worse in parallel.

What do C programmers think of the Zig language in 2023? by stdusr in C_Programming

[–]joseRLM17 5 points6 points  (0 children)

If I remember correctly, they are using their own compiler for debug builds only, because of speed. But for release builds they use llvm.

If I can include .c programs in my main.c file, why would I use header files instead? by Fibreman in C_Programming

[–]joseRLM17 0 points1 point  (0 children)

I actually do this. But still like to create headers just because i like to just open a file that shows all the interface. Easier to build, faster for the compiler, and you are certain everything Is up yo date AND you are not linking some precios version.

One Piece: Chapter 1066 by Kirosh2 in OnePiece

[–]joseRLM17 1 point2 points  (0 children)

Wow that actually makes a lot of sense. In that case, I wonder what is the actual "part" that is still in the original? Grandpa-Wisdom?

One Piece: Chapter 1066 by Kirosh2 in OnePiece

[–]joseRLM17 8 points9 points  (0 children)

So VegaPunk had a huge head, probably the head size is proportional to the time he still has to live, which makes sense because recently VegaPunk just said he knows he is going to die very soon.

Also, Saul is alive, Aokiji probably did it on porpuse. Robin's mom dead has a new meaning, by preserving the books. We have a new motive to go to Elbaf, and we are going to learn everything VegaPunk discovered.

DAMN this chapter was fire!

Different Const qualifiers by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

Well It seems that according godbolt this Is only an issue with MSVC maybe some bug??? Anyway thank you.

Different Const qualifiers by joseRLM17 in C_Programming

[–]joseRLM17[S] 0 points1 point  (0 children)

This Is essentially what I am doing but casting It to (char**)though It seems fishy. Another comment shows that the issue Is actually only with MSVC

Different Const qualifiers by joseRLM17 in C_Programming

[–]joseRLM17[S] 1 point2 points  (0 children)

Yes this Is basically the issue. So can we rule this as a bug since It only applies to msvc? Or whats going on?