Skip to main content
clarify
Source Link

Does that mean the following code is wrongcauses an undefined behavior? In this code, iterate_string takes a function of type processor_t and variable arguments follow this parameter.

Does that mean the following code is wrong? In this code, iterate_string takes a function of type processor_t and variable arguments follow this parameter.

Does that mean the following code causes an undefined behavior? In this code, iterate_string takes a function of type processor_t and variable arguments follow this parameter.

Source Link

The reason of there being constraints on the second argument of `va_start()`

I've found that there are conditions that the second argument of va_start(ap, last) must satisfy, which are:

  • last must not be a register variable
  • last must not be a function
  • last must not be an array

(Sources: stdarg(3), cppreference)

Though the manual page explains the reason these constraints exist, but I don't seem to understand the implication.

Does that mean the following code is wrong? In this code, iterate_string takes a function of type processor_t and variable arguments follow this parameter.

/*
 * A program that skips or reads some characters
 * from the external variable `src` and stores
 * them into `buf`.
 */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

/* External variables */
const char *src = "UwU Chino chan is so cute!!";
const int src_len = 22;
int src_idx = 0;  /* position in src */

char ch, buf[128];
int buf_idx;      /* position in buf */

/* Typedefs */
typedef int processor_t(va_list *ap_ptr);
typedef int checker_t(va_list *ap_ptr);

/*
 * Iterate 'src' by invoking `process`.
 * If `process` returns 0, stops the iteration.
 */
void iterate_string(processor_t process, ...) {
   va_list ap_is;  /* is = iterate string */

   while (src_idx < src_len) {
      va_start(ap_is, process);
      if (!process(&ap_is))
         break;
   }
   va_end(ap_is);
   return;
}

/*
 * Store a character into `buf`.
 * If `check` returns 0, stops the storing.
 */
int process_storing(va_list *ap_ptr) {
   checker_t *check;

   check = va_arg(*ap_ptr, checker_t *);

   ch = src[src_idx++];
   if ((*check)(ap_ptr)) {
      buf[buf_idx++] = ch;
      return 1;
   }
   else {
      buf[buf_idx] = '\0';
      return 0;
   }
}

/*
 * Just skip a character.
 * If `check` returns 0, stops the skipping.
 */
int process_leaving(va_list *ap_ptr) {
   checker_t *check;

   check = va_arg(*ap_ptr, checker_t *);

   ch = src[src_idx];
   if ((*check)(ap_ptr)) {
      src_idx++;
      return 1;
   }
   else
      return 0;
}

/*
 * Sees whether `cnt` is less than a number.
 * If not, returns.
 */
int check_count_less_than(va_list *ap_ptr) {
   static int cnt = 0;
   int n;

   n = va_arg(*ap_ptr, int);
   if (cnt < n) {
      cnt++;
      return 1;
   }
   else {
      cnt = 0;
      return 0;
   }
}

/*
 * Read `src` and store `n` characters into `buf`.
 */
void store_nchar(int n) {
   buf_idx = 0;
   iterate_string(process_storing, check_count_less_than, n);
}

/*
 * Read `src` and skip `n` characters.
 */
void leave_nchar(int n) {
   iterate_string(process_leaving, check_count_less_than, n);
}

int main(void) {
   leave_nchar(4); /* Skip "UwU " */
   store_nchar(5); /* Save "Chino" */

   // Daily greetings
   printf("Me: Hi, %s chan! How are you today?\n", buf);
   printf("%s: I'm sorry... Do I know you?\n", buf);

   return 0;
}

Although this code seems working (at least in my machine) but I'm not sure whether my code is good or bad. Should I have iterate_string have a pointer to processor_t? Please explain as easy as possible.