Skip to content

Instantly share code, notes, and snippets.

@ashafq
Created December 6, 2016 18:59
Show Gist options
  • Save ashafq/debc4b50d5222decc75bedd185d3d7fd to your computer and use it in GitHub Desktop.
Save ashafq/debc4b50d5222decc75bedd185d3d7fd to your computer and use it in GitHub Desktop.
/* I always wondered how variable length arguments worked in C.
* So, I just ended up implementing it in x86.
* NOTE: THIS CODE BELOW ONLY WORKS IN x86, AND NOT TESTED IN ANY OTHER ARCHITECTURE.
*
* To compile:
* gcc -Wall -o prog vargs.c && ./prog
* >> Testing: Hello world 10 -100
*/
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
static void print(const char *fmt, ...);
int main()
{
print("Testing: %s\t%d\t%d\n", "Hello world", 10, -100);
return 0;
}
static void print_char(char d);
static void print_str(char *x);
static void print_dec(int x);
static void print(const char *fmt, ...)
{
const char *s;
/* va_list args; */
unsigned char *args;
if (!fmt)
return;
/* va_start(args, fmt); */
/* Get the address of the stack and offset first argument.
* Note: Stack grows downwards (subtraction of pointe
*/
args = ((unsigned char *)&fmt) + sizeof(fmt);
s = fmt;
while (*s != '\0') /* traverse through the format str */
{
/* Print chars until the first % */
while (*s != '%' && *s != '\0')
print_char(*s++);
s++; /* Up to '%', grab next char */
switch (*s) { /* Switch format */
case 's':
{
/* char *ptr = va_arg(args, char *); */
char *ptr = *((char **)args);
args += sizeof(char *);
print_str(ptr);
s++;
break;
}
case 'd':
{
/* int d = va_arg(args, int); */
int d = *((int *)args);
args += sizeof(int);
print_dec(d);
s++;
break;
}
} /* end: switch(*s) */
}
/* va_end(args); */
}
#include <unistd.h>
static void print_char(char d)
{
write(STDOUT_FILENO, &d, sizeof(char)); /* Really bad. But... eh. */
}
static size_t str_len(char *x)
{
char *p = x;
while (*p != '\0') ++p;
return (p - x);
}
static void print_str(char *x)
{
write(STDOUT_FILENO, x, str_len(x));
}
static void print_dec(int x)
{
char buffer[16];
char sign = '\0';
if (x < 0) {
sign = '-';
x = -x;
}
char *ptr = buffer + 15;
*ptr-- = '\0';
while (x) {
*ptr-- = '0' + (x % 10);
x /= 10;
}
if (sign)
*ptr = sign;
else
ptr++;
print_str(ptr);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment