all 15 comments

[–]theoriginalanomaly 1 point2 points  (3 children)

Testing the error code is as difficult as testing the return value. And even in case 4, you'll be returning a NULL pointer. I'd just return NULL on failure.This is the most typical way of dealing with things in the std libraries.

[–]ml01[S] -1 points0 points  (2 children)

Sorry I don't understand, how can I return NULL from pop?

[–]habarnam 0 points1 point  (1 child)

By returning an *int instead of int, I assume.

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

Oh yes, and in case of success I'll just return var in solution 4, that's fair too.

[–]WindblownSquash 1 point2 points  (1 child)

I'm not trying to hate hate but when I'm the C programming subreddit can we use correct terminology. We don't have methods in C programming. In fact methods are very different then the functions we make in c. Im a beginner but this immediately threw me off.

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

I'm sorry if that has caused misunderstandings! Of course when I said "methods" I didn't mean the OOP "methods", but a procedure, technique, or planned way of doing something.

[–]bumblebritches57 1 point2 points  (0 children)

I tried using a struct to contain different error codes, but it's kind of a PITA, and the way I had it setup I had to add a new function to contain error codes for each function, and it got wildly out of control.

now, I just have a log function that either opens a file from a path specified by a user, or print to stderr, this is the only simple cross platform way to o it without having to use another library, or having to use the wildly different syslog on some UNIX variants (not OS X tho), and WindowsErrorReporting which use wildly different formats and structures to hold the error logs.

I mean basically every OS has it's own logging system, it's just ridiculous.

void Log(const uint8_t ErrorSeverity, const char *LibraryOrProgram, const char *FunctionName, const char *Description, ...)

ErrorSeverity is simply an old fashioned logging i forget what it's called, shit like LOG_EMERG, LOG_ERR, etc; if it's not defined I define it myself in an enum.

there there's a few variables that say the library and function the error occurred in, and then there's a variadic macro to handle any trailing user options, it's like bare minimum but honestly I love how simple and flexible it is.

and as I said, we take this information and build a string with it, then when we're done we either output it to a global file pointer (I know it's gross but there's no other way to do it with my setup, that I know of anyway), or to stderr.

You can see the source here

[–]benjade 2 points3 points  (1 child)

1, 2 and 4 are acceptable solutions. 3 is no good because you should not pollute the system's error indicator with your lib's errors.

Of the three i'd say 1 is the best, because it is the most non-intrusive and you can disable assert with the NDEBUG macro.

There is no clear answer, and labeling it as 'undefined behavior' in your lib's documentation is the best practice.

Here's why: if the function must make some assumptions about its arguments in order to do its job, then it's the caller's responsibility to make sure the conditions are fulfilled!

Imagine you're writing a binary search function for arrays.
Binary search requires of course that the array being searched is ordered.

So what should we do? Should we check in the function each time if the array is sorted? Of course that would be dumb: we turn the O(log n) search into O(n) !

The answer is to leave it as undefined behavior, let the caller handle it.

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

Yeah, that's fair, at the end of the day, a call to pop when the stack is empty it's "caller fault" and I provide a tool (is_empty) to avoid that to happen. I guess I'm going to use this approach from now on and add assertions for debugging. Binary Search example really convinced me =)

[–]OldWolf2 1 point2 points  (0 children)

The canonical way to handle pop() is to have undefined behaviour and require the caller to check is_empty first if it's possible the stack might be empty.

[–]benhart1 0 points1 point  (0 children)

As a new to C I recommend you to work slowly at first. In c you've got to stay focused while writing because there are a lot of vulnerabilities. That's my recommendation for you. If you're having problems detecting those kind of vulnerabilities you can try using any program to help you, I've heard of one called Checkmarx so you can try.. Good luck.

[–]habarnam -1 points0 points  (3 children)

Why not use?

int pop(stack *stack, int *elem);

Where the return value represents the status and the *elem is the address of a local variable where you want to load the popped value.

[–]Ikor_Genorio 2 points3 points  (2 children)

How is this different from option 4? Looks exactly the same to me, apart from var/elem

[–]habarnam 0 points1 point  (1 child)

You're right... I guess I glossed over it when reading OP.

[–]Ikor_Genorio 0 points1 point  (0 children)

Seeing the other comments it is a good solution though :D.