Remix.run Logo
▲ gucci-on-fleek 2 hours ago

C has supported struct returns since at least C89:

  /* Compile with "gcc -std=c89 -pedantic -Wall -Wextra -Werror". */
  #include <errno.h>
  #include <stdio.h>
  #include <stdlib.h>
  
  typedef struct {
      double value;
      enum { NO_ERROR = 0, PARSE_ERROR, TOO_BIG } error;
  } result_t;
  
  static result_t parse_double(char const *str) {
      char *endptr;
      double parsed;
      result_t result;
  
      errno  = 0;
      parsed = strtod(str, &endptr);
  
      if (endptr == str) {
          result.value = 0.0;
          result.error = PARSE_ERROR;
      } else if (errno == ERANGE) {
          result.value = 0.0;
          result.error = TOO_BIG;
      } else {
          result.value = parsed;
          result.error = NO_ERROR;
      }
      return result;
  }
  
  int main(void) {
      result_t r;
  
      r = parse_double("1.23");
      printf("value: %f, error: %d\n", r.value, r.error);
  
      r = parse_double("abc");
      printf("value: %f, error: %d\n", r.value, r.error);
  
      r = parse_double("1e5000");
      printf("value: %f, error: %d\n", r.value, r.error);
  
      return 0;
  }
Needing to typedef a unique struct for every possible function return type isn't very ergonomic, but you can work around that with C23:

  // Compile with "gcc -std=c23 -pedantic -Wall -Wextra -Werror".
  #include <errno.h>
  #include <stdio.h>
  #include <stdlib.h>
  
  typedef enum {
      NO_ERROR = false,
      PARSE_ERROR,
      TOO_BIG,
  } errors;
  
  static struct { double value; errors error; } parse_double(char const *str) {
      errno         = 0;
      char *endptr  = nullptr;
      double parsed = strtod(str, &endptr);
  
      typeof(parse_double(str)) result;
      if (endptr == str) {
          result.value = 0.0;
          result.error = PARSE_ERROR;
      } else if (errno == ERANGE) {
          result.value = 0.0;
          result.error = TOO_BIG;
      } else {
          result.value = parsed;
          result.error = NO_ERROR;
      }
      return result;
  }
  
  int main() {
      auto r = parse_double("1.23");
      printf("value: %f, error: %d\n", r.value, r.error);
  
      r = parse_double("abc");
      printf("value: %f, error: %d\n", r.value, r.error);
  
      r = parse_double("1e5000");
      printf("value: %f, error: %d\n", r.value, r.error);
  
      return 0;
  }