I have a problem with function which should print any type of integer on my KS0108 lcd. Here the problem is: when i want to copy void* numb value to void* temp in first swtich - nothing happens. in second switch when use %I get 0. (value of void* numb is about 48 and type _uint8_t)
Code:
void glcd_WriteInt(void* numb, type type)
{
void* temp = 0;
int8_t buff[10];
int8_t size = 0;
int8_t flag = 1;
int8_t sign = 1;
switch(type)
{
case _int8_t: memcpy(temp, numb, sizeof(int8_t)); break;
case _int16_t: memcpy(temp, numb, sizeof(int16_t)); break;
case _int32_t: memcpy(temp, numb, sizeof(int32_t)); break;
case _int64_t: /*memcpy(temp, numb, sizeof(int64_t)); break;*/return; //if want 64 - uncomment
case _uint8_t: *(uint8_t*) temp = *(uint8_t*) numb/*memcpy(temp, numb, sizeof(uint8_t))*/; break;
case _uint16_t: memcpy(temp, numb, sizeof(uint16_t)); break;
case _uint32_t: memcpy(temp, numb, sizeof(uint32_t)); break;
case _uint64_t: /*memcpy(temp, numb, sizeof(uint64_t)); break;*/return; //if want 64 - uncomment
}
while(flag)
{
switch(type)
{
case _int8_t:
buff[size] = *(int8_t*) temp % 100;
flag = (*(int8_t*) temp /= 100) != 0;
break;
case _int16_t:
buff[size] = *(int16_t*) temp % 100;
flag = (*(int16_t*) temp /= 100) != 0;
break;
case _int32_t:
buff[size] = *(int32_t*) temp % 100;
flag = (*(int32_t*) temp /= 100) != 0;
break;
case _int64_t:
/*buff[size] = *(int64_t*) temp % 100; //if want 64 - uncomment
flag = (*(int64_t*) temp /= 100) != 0;*/
break;
case _uint8_t:
buff[size] = *(uint8_t*) temp % 100;
flag = (*(uint8_t*) temp /= 100) != 0;
break;
case _uint16_t:
buff[size] = *(uint16_t*) temp % 100;
flag = (*(uint16_t*) temp /= 100) != 0;
break;
case _uint32_t:
buff[size] = *(uint32_t*) temp % 100;
flag = (*(uint32_t*) temp /= 100) != 0;
break;
case _uint64_t:
/*buff[size] = *(uint64_t*) temp % 100; //if want 64 - uncomment
flag = (*(uint64_t*) temp /= 100) != 0;*/
break;
}
if(buff[size] < 0){
buff[size] = -buff[size];
sign = -1;
}
size++;
}
if(sign == -1) glcd_Character((char) 45);
glcd_WIntTab(buff, size);
}
I tried versions with memcpy, and like here: casts. It is suprising that this function was OK a few days ago.
Your main problem is that you have
void *temp = 0;
declared, and you try to write to a NULL pointer since you initialize it with void *temp = 0.
Even if you don't initialize it, it wont work because it wouldn't be a valid pointer, so either you allocate memory with malloc and assign it to the void *temp pointer, or use a union this way
union Type {
int8_t _int8_t;
int16_t _int16_t;
int32_t _int32_t;
int64_t _int64_t;
uint8_t _uint8_t;
uint16_t _uint16_t;
uint32_t _uint32_t;
uint64_t _uint64_t;
};
void glcd_WriteInt(void* numb, enum type type)
{
union Type temp;
int8_t buff[10];
int8_t size = 0;
int8_t flag = 1;
int8_t sign = 1;
switch (type)
{
case _int8_t: memcpy(&temp, numb, sizeof(int8_t)); break;
case _int16_t: memcpy(&temp, numb, sizeof(int16_t)); break;
case _int32_t: memcpy(&temp, numb, sizeof(int32_t)); break;
case _int64_t: /*memcpy(&temp, numb, sizeof(int64_t)); break;*/return; //if want 64 - uncomment
case _uint8_t: memcpy(&temp, numb, sizeof(uint8_t))/*memcpy(temp, numb, sizeof(uint8_t))*/; break;
case _uint16_t: memcpy(&temp, numb, sizeof(uint16_t)); break;
case _uint32_t: memcpy(&temp, numb, sizeof(uint32_t)); break;
case _uint64_t: /*memcpy(&temp, numb, sizeof(uint64_t)); break;*/return; //if want 64 - uncomment
}
while (flag)
{
switch (type)
{
case _int8_t:
buff[size] = temp._int8_t % 100;
flag = (temp._int8_t /= 100) != 0;
break;
case _int16_t:
buff[size] = temp._int16_t % 100;
flag = (temp._int16_t /= 100) != 0;
break;
case _int32_t:
buff[size] = temp._int32_t % 100;
flag = (temp._int32_t /= 100) != 0;
break;
case _int64_t:
buff[size] = temp._int64_t % 100;
flag = (temp._int64_t /= 100) != 0;
break;
case _uint8_t:
buff[size] = temp._uint8_t % 100;
flag = (temp._uint8_t /= 100) != 0;
break;
case _uint16_t:
buff[size] = temp._uint16_t % 100;
flag = (temp._uint16_t /= 100) != 0;
break;
case _uint32_t:
buff[size] = temp._uint32_t % 100;
flag = (temp._uint32_t /= 100) != 0;
break;
case _uint64_t:
buff[size] = temp._uint64_t % 100;
flag = (temp._uint64_t /= 100) != 0;
break;
}
if (buff[size] < 0)
{
buff[size] = -buff[size];
sign = -1;
}
size++;
}
if (sign == -1)
glcd_Character((char) 45);
glcd_WIntTab(buff, size);
}
I believe the union is a better solution.
Related
I'm making my own x86 OS using the i386-elf cross-compiler and linker and nasm to compile asm files. The OS itself runs with qemu. That being said, I made a custom print function but ran into a problem. Every time I access memory (either through the [] operator or by dereferencing a pointer) and call my print function afterwards, it leaves 8 blank spaces and then prints normally.
Print code:
void printv(char *str, ...)
{
unsigned int tmp_cursor = get_cursor_position();
cursor_position.x = (unsigned short)(tmp_cursor >> 16);
cursor_position.y = (unsigned short)tmp_cursor;
char buffer[12];
va_list list_ptr;
va_start(list_ptr, str);
unsigned int i = 0;
for (char *ptr = str; *ptr != '\0'; ptr++)
{
switch (*ptr)
{
case '%':
cursor_position.y += (cursor_position.x + i) / 80;
cursor_position.x = (cursor_position.x + i) % 80;
update_cursor(cursor_position.x, cursor_position.y);
i = 0;
switch (*(ptr + 1))
{
case 'c':
buffer[0] = (char)va_arg(list_ptr, int);
buffer[1] = '\0';
printv(buffer);
ptr++;
break;
case 's':
printv(va_arg(list_ptr, char *));
ptr++;
break;
case 'i':
case 'd':
int_to_str(va_arg(list_ptr, int), buffer, 10);
printv(buffer);
ptr++;
break;
default:
*(char*)(0xb8000 + (cursor_position.x + i + cursor_position.y * 80) * 2) = *ptr;
i++;
break;
}
break;
case '\n':
i = 0;
cursor_position.x = 0;
cursor_position.y++;
break;
case '\t':
cursor_position.y += (cursor_position.x + i) / 80;
cursor_position.x = (cursor_position.x + i) % 80;
update_cursor(cursor_position.x, cursor_position.y);
i = 0;
cursor_position.x += TAB_SPACE - cursor_position.x % TAB_SPACE - 1;
break;
default:
*(char *)(0xb8000 +(cursor_position.x + i + cursor_position.y * 80) * 2) = *ptr;
i++;
break;
}
}
va_end(list_ptr);
memset(buffer, '\0', 12);
cursor_position.y += (cursor_position.x + i) / 80;
cursor_position.x = (cursor_position.x + i) % 80;
update_cursor(cursor_position.x, cursor_position.y);
}
Call example:
printv("Starting PonchOS!\n");
char str[12];
for (int i = 0; i < 11; i++)
{
str[i] = 'a' + i;
}
str[11] = '\0';
printv("Testtesttesttesttest");
Output:
As you can see, it prints fine before any memory access, but after that, it leaves those white spaces. Any ideas as to why this happens?
Edit:
Implementing #chqrlie 's changes, some issues have been fixed, although spacing problems persist.
Code:
printv("Starting PonchOS!\n");
printv("%c\n", 'C');
printv("%i", 128);
printv("%s", "string");
Output:
The problem comes from your not updating the cursor variables consistently when calling printv recursively. Furthermore you would get undefined behavior for this call: printv("%s", "%s").
You should split the function into a high level one that handles the formatting and a low level one that draws a string to the screen.
Here is a modified version:
void putstr(const char *str, size_t n) {
if (n > 0) {
unsigned int tmp_cursor = get_cursor_position();
int x = (unsigned short)(tmp_cursor >> 16);
int y = (unsigned short)tmp_cursor;
size_t i;
for (i = 0; i < n; i++) {
switch (str[i]) {
case '\n':
y += x / 80 + 1;
x = 0;
break;
case '\r':
y += x / 80;
x = 0;
break;
case '\t':
x = (x + TAB_SPACE) / TAB_SPACE * TAB_SPACE;
y += x / 80;
x %= 80;
break;
default:
*(char *)(0xb8000 + (y * 80 + x) * 2) = str[i];
x++;
break;
}
}
update_cursor(x, y);
}
}
void printv(const char *str, ...) {
char buffer[32];
char *p;
const char *ptr;
va_list list_ptr;
va_start(list_ptr, str);
for (ptr = str; *ptr != '\0'; ptr++) {
if (*ptr == '%' && ptr[1] != '\0') {
putstr(str, ptr - str);
str = ptr;
ptr++;
switch (*ptr) {
case 'c':
buffer[0] = (char)va_arg(list_ptr, int);
putstr(buffer, 1);
str += 2; // skip the format
break;
case 's':
p = va_arg(list_ptr, char *);
putstr(p, strlen(p));
str += 2; // skip the format
break;
case 'i':
case 'd':
int_to_str(va_arg(list_ptr, int), buffer, 10);
putstr(buffer, strlen(buffer));
str += 2; // skip the format
break;
case '%':
str += 1; // skip the initial %
break;
}
}
}
putstr(str, ptr - str);
va_end(list_ptr);
}
I decided to write another one BF interpreter in order of personal development, and despite the fact that this is his second version written from scratch, one way or another it doesn't work correctly with cycles. Please tell me how this can be rewritten, or what is the logical problem. Below is the code and examples of programs in BF.
#include <stdio.h>
void brainfuck(char* str, int length)
{
char arr[30000] = { 0 };
int ptr = 0, i = 0;
int **brackets = { 0 };
int br_len = 0;
while (i < length)
{
if (str[i] == '[')
{
brackets = (int **)realloc(brackets, (br_len + 1) * sizeof(int *));
brackets[br_len] = (int *)malloc(2 * sizeof(int));
brackets[br_len][0] = '[';
brackets[br_len][1] = i;
br_len++;
}
else if (str[i] == ']')
{
brackets = (int **)realloc(brackets, (br_len + 1) * sizeof(int *));
brackets[br_len] = (int *)malloc(2 * sizeof(int));
brackets[br_len][0] = ']';
brackets[br_len][1] = i;
br_len++;
}
i++;
}
int counter, pos, j; i = 0;
while (i < length)
{
switch (str[i])
{
case '>': ptr++; break;
case '<': ptr--; break;
case '+': arr[ptr]++; break;
case '-': arr[ptr]--; break;
case '.': putchar(arr[ptr]); break;
case ',': arr[ptr] = getchar(); break;
case '[':
if (arr[ptr] == 0)
{
j = 0;
pos = 0;
do
{
pos = j;
j++;
}
while (brackets[j - 1][1] != i);
j = pos + 1;
counter = 1;
while (j < br_len)
{
if (brackets[j][0] == '[')
counter++;
else if (brackets[j][0] == ']')
{
counter--;
if (counter == 0)
break;
}
j++;
}
i = brackets[j][1];
}
break;
case ']':
if (arr[ptr] == 0)
{
j = br_len - 1;
pos = br_len - 1;
do
{
pos = j;
j--;
} while (brackets[j + 1][1] != i);
j = pos - 1;
counter = -1;
while (j >= 0)
{
if (brackets[j][0] == '[')
{
counter++;
if (counter == 0)
break;
}
else if (brackets[j][0] == ']')
counter--;
j--;
}
i = brackets[j][1] - 1;
}
break;
default: break;
}
i++;
}
free(brackets);
}
void main()
{
FILE* fr;
int length;
char* str;
fr = fopen("input.txt", "r");
fseek(fr, 0, SEEK_END);
length = ftell(fr);
rewind(fr);
str = (char*)malloc(length * sizeof(char));
fread(str, 1, length, fr);
brainfuck(str, length);
free(str);
fclose(fr);
}
"Hello World!" with one loop
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
------.--------.>+.>.
"Hello World!" with nested loops
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
']' should jump back if cell is nonzero
Hugely convoluted approach; you want to put the matches in the brackets array so it's like
case '[':
if (arr[ptr] == 0)
i = brackets[i];
break;
Why i = brackets[j][1] - 1; and not just i = brackets[j][1]; (extra speed cost)
Having j and pos laboriously correlate is a red flag
Forgot to free all those little 2-int arrays
I am writing a function
int are_non_negatives(int* start, int n) {
...
}
This function returns 1 if all the next n integers in the array start are non-negative. It returns 0 otherwise.
My question is if there exist tricks that do this as fast as possible (other than looping and checking every single position)?
Dirty/non-portable tricks are fine. I want to know about those as well. Thanks!
One slightly "dirty/non-portable" trick you could leverage for the worst case where all elements need to be checked: In 2's complement int representation, the highest bit is set if and only if the value is negative. So, you could bitwise OR them all and check the highest bit. This could be done using vector instructions to do batches of them at a time, e.g. 8 elements at a time supposing 32-bit int and 256-bit AVX instructions.
Trying to improve performance is a recurring subject for C programmers. Benchmarking alternatives is necessary to test if optimization is useful and worth the effort. This is a naive implementation for reference:
int are_non_negatives_naive(const int *start, int n) {
while (n --> 0) {
if (*start++ >= 0)
return 0;
}
return 1;
}
On current architectures (two's complement) you can combine blocks of entries and test the sign bit much less often. If the arrays are small, you can combine all elements and use a single test:
int are_non_negatives_full(const int *start, int n) {
int combined = 0;
while (n --> 0) {
combined |= *start++;
}
return combined >= 0;
}
If the arrays sizes are varied, you can combine all elements in chunks and test every chunk, allowing for early bail out if a negative value is present:
int are_non_negatives_chunks(const int *start, int n) {
int combined;
for (; n >= 8; n -= 8, start += 8) {
combined = (start[0] | start[1] | start[2] | start[3] |
start[4] | start[5] | start[6] | start[7]);
if (combined < 0)
return 0;
}
combined = 0;
while (n --> 0) {
combined |= *start++;
}
return combined >= 0;
}
Further performance improvements can be achieved by vectorizing the above, either using portable constructions such using 64-bit types or more specific hardware specific intrinsics. The effort might not be necessary is the compiler can vectorize the above algorithms on its own: clang uses SIMD instructions as can be seen with Godbolt Compiler Explorer.
You could check k elements at a time by casting to the largest integer available and crafting the right mask, eg: if you have an array of char, or int8_t, you could check 8 elements at a time.
The mask is crafted to be all zeroes, except for the sign bits.
This way if one of those chars is negative the bitwise AND of the mask and the cast iterator will be > 0
int8_t _i8[8] = { INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN };
uint64_t mask = *(uint64_t *)_i8;
uint64_t *it = (uint64_t *)a;
size_t i = 0;
if (it[i] & mask)
return FALSE;
Of course you should take care of the remainders of n % k, which can be done with a simple switch like this:
size_t i = 0;
switch (n % 8) {
case 0: if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
}
Here I've made a proof of concept that compares the naive approach, the unrolled approach using the Duff's device, and an unrolled and masked approach that uses both the Duff's device and the masking.
It would require a bit more testing, but seems promising nonetheless.
You can run it here https://onlinegdb.com/SyliIUrSZO
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#define CLOCKS_PER_MSEC (CLOCKS_PER_SEC/1000)
#define TRUE (0 == 0)
#define FALSE (!TRUE)
// 8 bit integers
int are_non_negatives_naive_i8(int8_t *a, size_t n)
{
size_t i;
for (i = 0; i < n; ++i)
if (a[i] < 0)
return FALSE;
return TRUE;
}
int are_non_negatives_unrolled_i8(int8_t *a, size_t n)
{
size_t M = (n + 7) / 8;
size_t i = 0;
switch (n % 8) {
case 0: do { if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
} while (--M > 0);
}
}
int are_non_negatives_unrolled_masked_i8(int8_t *a, size_t n)
{
int8_t _i8[8] = { INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN, INT8_MIN };
uint64_t mask = *(uint64_t *)_i8;
uint64_t *it = (uint64_t *)a;
size_t i = 0;
switch (n % 8) {
case 0: if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
}
size_t N = n / 8;
// for (i = 0; i < N; ++i)
// if (it[i] & mask)
// return FALSE;
size_t M = (N + 7) / 8;
switch (N % 8) {
case 0: do { if (it[i++] & mask) return FALSE;
case 7: if (it[i++] & mask) return FALSE;
case 6: if (it[i++] & mask) return FALSE;
case 5: if (it[i++] & mask) return FALSE;
case 4: if (it[i++] & mask) return FALSE;
case 3: if (it[i++] & mask) return FALSE;
case 2: if (it[i++] & mask) return FALSE;
case 1: if (it[i++] & mask) return FALSE;
} while (--M > 0);
}
return TRUE;
}
//----------------------------------------------------------------
// 16 bit integers
int are_non_negatives_naive_i16(int16_t *a, size_t n)
{
size_t i;
for (i = 0; i < n; ++i)
if (a[i] < 0)
return FALSE;
return TRUE;
}
int are_non_negatives_unrolled_i16(int16_t *a, size_t n)
{
size_t M = (n + 7) / 8;
size_t i = 0;
switch (n % 8) {
case 0: do { if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
} while (--M > 0);
}
}
int are_non_negatives_unrolled_masked_i16(int16_t *a, size_t n)
{
int16_t _i16[4] = { INT16_MIN, INT16_MIN, INT16_MIN, INT16_MIN };
uint64_t mask = *(uint64_t *)_i16;
uint64_t *it = (uint64_t *)a;
size_t i = 0;
switch (n % 8) {
case 0: if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
}
size_t N = n / 4;
// for (i = 0; i < N; ++i)
// if (it[i] & mask)
// return FALSE;
size_t M = (N + 7) / 8;
switch (N % 8) {
case 0: do { if (it[i++] & mask) return FALSE;
case 7: if (it[i++] & mask) return FALSE;
case 6: if (it[i++] & mask) return FALSE;
case 5: if (it[i++] & mask) return FALSE;
case 4: if (it[i++] & mask) return FALSE;
case 3: if (it[i++] & mask) return FALSE;
case 2: if (it[i++] & mask) return FALSE;
case 1: if (it[i++] & mask) return FALSE;
} while (--M > 0);
}
return TRUE;
}
//----------------------------------------------------------------
// 32 bit integers
int are_non_negatives_naive_i32(int32_t *a, size_t n)
{
size_t i;
for (i = 0; i < n; ++i)
if (a[i] < 0)
return FALSE;
return TRUE;
}
int are_non_negatives_unrolled_i32(int32_t *a, size_t n)
{
size_t M = (n + 7) / 8;
size_t i = 0;
switch (n % 8) {
case 0: do { if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
} while (--M > 0);
}
}
int are_non_negatives_unrolled_masked_i32(int32_t *a, size_t n)
{
int32_t _i32[2] = { INT32_MIN, INT32_MIN };
uint64_t mask = *(uint64_t *)_i32;
uint64_t *it = (uint64_t *)a;
size_t i = 0;
switch (n % 8) {
case 0: if (a[i++] < 0) return FALSE;
case 7: if (a[i++] < 0) return FALSE;
case 6: if (a[i++] < 0) return FALSE;
case 5: if (a[i++] < 0) return FALSE;
case 4: if (a[i++] < 0) return FALSE;
case 3: if (a[i++] < 0) return FALSE;
case 2: if (a[i++] < 0) return FALSE;
case 1: if (a[i++] < 0) return FALSE;
}
size_t N = n / 2;
// for (i = 0; i < N; ++i)
// if (it[i] & mask)
// return FALSE;
size_t M = (N + 7) / 8;
switch (N % 8) {
case 0: do { if (it[i++] & mask) return FALSE;
case 7: if (it[i++] & mask) return FALSE;
case 6: if (it[i++] & mask) return FALSE;
case 5: if (it[i++] & mask) return FALSE;
case 4: if (it[i++] & mask) return FALSE;
case 3: if (it[i++] & mask) return FALSE;
case 2: if (it[i++] & mask) return FALSE;
case 1: if (it[i++] & mask) return FALSE;
} while (--M > 0);
}
return TRUE;
}
//----------------------------------------------------------------
void fill_array(void *array, size_t type, size_t n, int contains_negatives)
{
size_t i;
switch (type) {
case 1: {
int8_t *a = array;
for (i = 0; i < n; ++i)
a[i] = rand() % INT8_MAX;
break;
}
case 2: {
int16_t *a = array;
for (i = 0; i < n; ++i)
a[i] = rand() % INT16_MAX;
break;
}
case 4: {
int32_t *a = array;
for (i = 0; i < n; ++i)
a[i] = rand() % INT32_MAX;
break;
}
case 8: {
int64_t *a = array;
for (i = 0; i < n; ++i)
a[i] = rand();
break;
}
}
if (contains_negatives) {
int how_many = rand() % n;
for (int i; i < how_many; ++i) {
int j = rand() % n;
switch (type) {
case 1: {
int8_t *a = array;
a[j] *= -1;
break;
}
case 2: {
int16_t *a = array;
a[j] *= -1;
break;
}
case 4: {
int32_t *a = array;
a[j] *= -1;
break;
}
case 8: {
int64_t *a = array;
a[j] *= -1;
break;
}
}
}
}
}
int main()
{
time_t t;
clock_t clock_start;
clock_t clock_end;
clock_t clock_naive = 0;
clock_t clock_unrolled = 0;
clock_t clock_unrolled_masked = 0;
/* Intializes random number generator */
srand((unsigned long) time(&t));
printf("8 bit integers\n");
printf("----------------------------------------------------------------\n");
int8_t *array_i8;
for (int i = 3; i < 7; ++i) {
size_t size = pow(10, i);
array_i8 = malloc(size * sizeof(int8_t));
printf("------------------------------------------------\n");
printf("%lu elements\n", size);
for (int has_neg = 0; has_neg < 2; ++has_neg) {
printf("--------------------------------\n");
printf("Has negatives: %s\n", has_neg ? "yes": "no");
fill_array(array_i8, sizeof(int8_t), size, has_neg);
int neg_naive;
int neg_unrolled;
int neg_unrolled_masked;
clock_start = clock();
neg_naive = are_non_negatives_naive_i8(array_i8, size);
clock_end = clock();
clock_naive = clock_end - clock_start;
clock_start = clock();
neg_unrolled = are_non_negatives_unrolled_i8(array_i8, size);
clock_end = clock();
clock_unrolled = clock_end - clock_start;
clock_start = clock();
neg_unrolled_masked = are_non_negatives_unrolled_masked_i8(array_i8, size);
clock_end = clock();
clock_unrolled_masked = clock_end - clock_start;
if (!has_neg) {
if (!neg_naive)
printf("Error: neg_naive\n");
if (!neg_unrolled)
printf("Error: neg_unrolled\n");
if (!neg_unrolled_masked)
printf("Error: neg_unrolled_masked\n");
}
printf(" clock_naive: %lu\n", clock_naive);
printf(" clock_unrolled: %lu\n", clock_unrolled);
printf("clock_unrolled_masked: %lu\n", clock_unrolled_masked);
printf("--------------------------------\n");
}
printf("------------------------------------------------\n");
free (array_i8);
array_i8 = NULL;
}
printf("----------------------------------------------------------------\n");
printf("16 bit integers\n");
printf("----------------------------------------------------------------\n");
int16_t *array_i16;
for (int i = 3; i < 7; ++i) {
size_t size = pow(10, i);
array_i16 = malloc(size * sizeof(int16_t));
printf("------------------------------------------------\n");
printf("%lu elements\n", size);
for (int has_neg = 0; has_neg < 2; ++has_neg) {
printf("--------------------------------\n");
printf("Has negatives: %s\n", has_neg ? "yes": "no");
fill_array(array_i16, sizeof(int16_t), size, has_neg);
int neg_naive;
int neg_unrolled;
int neg_unrolled_masked;
clock_start = clock();
neg_naive = are_non_negatives_naive_i16(array_i16, size);
clock_end = clock();
clock_naive = clock_end - clock_start;
clock_start = clock();
neg_unrolled = are_non_negatives_unrolled_i16(array_i16, size);
clock_end = clock();
clock_unrolled = clock_end - clock_start;
clock_start = clock();
neg_unrolled_masked = are_non_negatives_unrolled_masked_i16(array_i16, size);
clock_end = clock();
clock_unrolled_masked = clock_end - clock_start;
if (!has_neg) {
if (!neg_naive)
printf("Error: neg_naive\n");
if (!neg_unrolled)
printf("Error: neg_unrolled\n");
if (!neg_unrolled_masked)
printf("Error: neg_unrolled_masked\n");
}
printf(" clock_naive: %lu\n", clock_naive);
printf(" clock_unrolled: %lu\n", clock_unrolled);
printf("clock_unrolled_masked: %lu\n", clock_unrolled_masked);
printf("--------------------------------\n");
}
printf("------------------------------------------------\n");
free (array_i16);
array_i16 = NULL;
}
printf("----------------------------------------------------------------\n");
printf("32 bit integers\n");
printf("----------------------------------------------------------------\n");
int32_t *array_i32;
for (int i = 3; i < 7; ++i) {
size_t size = pow(10, i);
array_i32 = malloc(size * sizeof(int32_t));
printf("------------------------------------------------\n");
printf("%lu elements\n", size);
for (int has_neg = 0; has_neg < 2; ++has_neg) {
printf("--------------------------------\n");
printf("Has negatives: %s\n", has_neg ? "yes": "no");
fill_array(array_i32, sizeof(int32_t), size, has_neg);
int neg_naive;
int neg_unrolled;
int neg_unrolled_masked;
clock_start = clock();
neg_naive = are_non_negatives_naive_i32(array_i32, size);
clock_end = clock();
clock_naive = clock_end - clock_start;
clock_start = clock();
neg_unrolled = are_non_negatives_unrolled_i32(array_i32, size);
clock_end = clock();
clock_unrolled = clock_end - clock_start;
clock_start = clock();
neg_unrolled_masked = are_non_negatives_unrolled_masked_i32(array_i32, size);
clock_end = clock();
clock_unrolled_masked = clock_end - clock_start;
if (!has_neg) {
if (!neg_naive)
printf("Error: neg_naive\n");
if (!neg_unrolled)
printf("Error: neg_unrolled\n");
if (!neg_unrolled_masked)
printf("Error: neg_unrolled_masked\n");
}
printf(" clock_naive: %lu\n", clock_naive);
printf(" clock_unrolled: %lu\n", clock_unrolled);
printf("clock_unrolled_masked: %lu\n", clock_unrolled_masked);
printf("--------------------------------\n");
}
printf("------------------------------------------------\n");
free (array_i32);
array_i32 = NULL;
}
printf("----------------------------------------------------------------\n");
}
Any suggestions or fixes are more than welcome
Note that this solution is not standard and depends on the alignment of the data types.
Albeit it'll usually work, you should check it with something like this
#include <stdio.h>
#include <stdint.h>
#include <stdalign.h>
int main()
{
printf(
"alignof(int8_t ): %lu\n"
"alignof(int16_t): %lu\n"
"alignof(int32_t): %lu\n"
"alignof(int64_t): %lu\n",
alignof(int8_t),
alignof(int16_t),
alignof(int32_t),
alignof(int64_t)
);
return 0;
}
I suspect that this won’t work for you based on the context of your question, but in case your code allows for you to capture array operations (initialization, insertion, modification, deletion), you can coherently maintain a separate list of all elements with negative values. If you have the freedom to do that, it would just be a space-speed tradeoff.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "stack.h"
#define MAX_EQU_LEN 100
static int prec(char operator)
{
switch (operator)
{
case '*':
return 5;
case '/':
return 4;
case '%':
return 3;
case '+':
return 2;
case '-':
return 1;
default:
break;
}
return 0;
}
static int isNumeric(char* num)
{
if(atoi(num) == 0)
{
return 0;
}
return 1;
}
char* infix_to_postfix(char* infix)
{
char* postfix = malloc(MAX_EQU_LEN);
stack* s = create_stack();
s->size = strlen(infix);
node* tempPtr = s->stack;
unsigned int i;
char symbol,next;
for(i = 0; i < s->size ; i++)
{
symbol = *((infix + i));
tempPtr = s->stack;
if(isNumeric(&symbol) != 1)
{
strcat(postfix, &symbol);
}
else if(symbol == '(')
{
push(s, symbol);
}
else if(symbol == ')')
{
while(s->size != 0 && top(s) != '(')
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
tempPtr = s->stack;
if(tempPtr->data == '(')
{
pop(s);
}
}
}
else
{
while(s->size != 0 && prec(top(s)) > prec(symbol))
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
push(s,next);
}
}
while(s->size != 0)
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
}
}
return postfix;
}
int evaluate_postfix(char* postfix) {
//For each token in the string
int i,result;
int right, left;
char ch;
stack* s = create_stack();
node* tempPtr = s->stack;
for(i=0;postfix[i] < strlen(postfix); i++){
//if the token is numeric
ch = postfix[i];
if(isNumeric(&ch)){
//convert it to an integer and push it onto the stack
atoi(&ch);
push(s, ch);
}
else
{
pop(&s[i]);
pop(&s[i+1]);
//apply the operation:
//result = left op right
switch(ch)
{
case '+': push(&s[i],right + left);
break;
case '-': push(&s[i],right - left);
break;
case '*': push(&s[i],right * left);
break;
case '/': push(&s[i],right / left);
break;
}
}
}
tempPtr = s->stack;
//return the result from the stack
return(tempPtr->data);
}
This file is part of a program that uses a stack struct to perform an infix to postfix on an input file. The other functions have been tested and work fine but when I try to add this part and actually perform the operations the program segmentation faults. A debugger says it occurs in the infix_to_postfix function however it doesn't say which line and I can't figure out where. Does anyone know why this would seg fault?
You've done a few things wrong:
if(isNumeric(&symbol) != 1)
The function isNumeric() expects a null terminated string as input, not a pointer to a single character.
strcat(postfix, &symbol);
Here the same thing applies.
strcat(postfix, &next);
I'm guessing this is wrong too. If you want to turn a single character into a string, you can do this:
char temp[2] = {0};
temp[0] = symbol;
strcat(postfix, temp);
static int isNumeric(char* num)
{
if(atoi(num) == 0)
{
return 0;
}
return 1;
}
What if the string is "0"? Consider using strtol instead because it offers a more powerful means of testing the success of the outcome.
An unrelated stylistic note: your first function looks overcomplicated to me. Although it's perfectly possible that the way I'd do it is also overcomplicated.
static int prec(char operator)
{
switch (operator)
{
case '*':
return 5;
case '/':
return 4;
case '%':
return 3;
case '+':
return 2;
case '-':
return 1;
default:
break;
}
return 0;
}
If a function performs a simple mapping from one set to another, It could usually be performed more simply (and faster) as an array lookup. So I'd start with a string of the input characters.
char *operators = "*" "/" "%" "+" "-";
Note that the compiler will concatenate these to a single string value with a null-terminator.
int precedence[] = { 5, 4, 3, 2, 1, 0 };
Then testing whether a char is an operator is:
#include <string.h>
if (strchr(operators, chr))
...;
And getting the precedence becomes:
p = precedence[strchr(operators, chr) - operators];
If there are more values to associate with the operator, I'd consider using an X-Macro to generate a table and a set of associated enum values to use as symbolic indices.
The code below is extracted from nginx,which basically rewrites sprintf,in fact nginx also rewrites some other string functions,is it worth the effort?
u_char *
ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
{
u_char *p, zero;
int d;
double f, scale;
size_t len, slen;
int64_t i64;
uint64_t ui64;
ngx_msec_t ms;
ngx_uint_t width, sign, hex, max_width, frac_width, n;
ngx_str_t *v;
ngx_variable_value_t *vv;
while (*fmt && buf < last) {
/*
* "buf < last" means that we could copy at least one character:
* the plain character, "%%", "%c", and minus without the checking
*/
if (*fmt == '%') {
i64 = 0;
ui64 = 0;
zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
width = 0;
sign = 1;
hex = 0;
max_width = 0;
frac_width = 0;
slen = (size_t) -1;
while (*fmt >= '0' && *fmt <= '9') {
width = width * 10 + *fmt++ - '0';
}
for ( ;; ) {
switch (*fmt) {
case 'u':
sign = 0;
fmt++;
continue;
case 'm':
max_width = 1;
fmt++;
continue;
case 'X':
hex = 2;
sign = 0;
fmt++;
continue;
case 'x':
hex = 1;
sign = 0;
fmt++;
continue;
case '.':
fmt++;
while (*fmt >= '0' && *fmt <= '9') {
frac_width = frac_width * 10 + *fmt++ - '0';
}
break;
case '*':
slen = va_arg(args, size_t);
fmt++;
continue;
default:
break;
}
break;
}
switch (*fmt) {
case 'V':
v = va_arg(args, ngx_str_t *);
len = ngx_min(((size_t) (last - buf)), v->len);
buf = ngx_cpymem(buf, v->data, len);
fmt++;
continue;
case 'v':
vv = va_arg(args, ngx_variable_value_t *);
len = ngx_min(((size_t) (last - buf)), vv->len);
buf = ngx_cpymem(buf, vv->data, len);
fmt++;
continue;
case 's':
p = va_arg(args, u_char *);
if (slen == (size_t) -1) {
while (*p && buf < last) {
*buf++ = *p++;
}
} else {
len = ngx_min(((size_t) (last - buf)), slen);
buf = ngx_cpymem(buf, p, len);
}
fmt++;
continue;
case 'O':
i64 = (int64_t) va_arg(args, off_t);
sign = 1;
break;
case 'P':
i64 = (int64_t) va_arg(args, ngx_pid_t);
sign = 1;
break;
case 'T':
i64 = (int64_t) va_arg(args, time_t);
sign = 1;
break;
case 'M':
ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
if ((ngx_msec_int_t) ms == -1) {
sign = 1;
i64 = -1;
} else {
sign = 0;
ui64 = (uint64_t) ms;
}
break;
case 'z':
if (sign) {
i64 = (int64_t) va_arg(args, ssize_t);
} else {
ui64 = (uint64_t) va_arg(args, size_t);
}
break;
case 'i':
if (sign) {
i64 = (int64_t) va_arg(args, ngx_int_t);
} else {
ui64 = (uint64_t) va_arg(args, ngx_uint_t);
}
if (max_width) {
width = NGX_INT_T_LEN;
}
break;
case 'd':
if (sign) {
i64 = (int64_t) va_arg(args, int);
} else {
ui64 = (uint64_t) va_arg(args, u_int);
}
break;
case 'l':
if (sign) {
i64 = (int64_t) va_arg(args, long);
} else {
ui64 = (uint64_t) va_arg(args, u_long);
}
break;
case 'D':
if (sign) {
i64 = (int64_t) va_arg(args, int32_t);
} else {
ui64 = (uint64_t) va_arg(args, uint32_t);
}
break;
case 'L':
if (sign) {
i64 = va_arg(args, int64_t);
} else {
ui64 = va_arg(args, uint64_t);
}
break;
case 'A':
if (sign) {
i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
} else {
ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
}
if (max_width) {
width = NGX_ATOMIC_T_LEN;
}
break;
case 'f':
f = va_arg(args, double);
if (f < 0) {
*buf++ = '-';
f = -f;
}
ui64 = (int64_t) f;
buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
if (frac_width) {
if (buf < last) {
*buf++ = '.';
}
scale = 1.0;
for (n = frac_width; n; n--) {
scale *= 10.0;
}
/*
* (int64_t) cast is required for msvc6:
* it can not convert uint64_t to double
*/
ui64 = (uint64_t) ((f - (int64_t) ui64) * scale + 0.5);
buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
}
fmt++;
continue;
#if !(NGX_WIN32)
case 'r':
i64 = (int64_t) va_arg(args, rlim_t);
sign = 1;
break;
#endif
case 'p':
ui64 = (uintptr_t) va_arg(args, void *);
hex = 2;
sign = 0;
zero = '0';
width = NGX_PTR_SIZE * 2;
break;
case 'c':
d = va_arg(args, int);
*buf++ = (u_char) (d & 0xff);
fmt++;
continue;
case 'Z':
*buf++ = '\0';
fmt++;
continue;
case 'N':
#if (NGX_WIN32)
*buf++ = CR;
#endif
*buf++ = LF;
fmt++;
continue;
case '%':
*buf++ = '%';
fmt++;
continue;
default:
*buf++ = *fmt++;
continue;
}
if (sign) {
if (i64 < 0) {
*buf++ = '-';
ui64 = (uint64_t) -i64;
} else {
ui64 = (uint64_t) i64;
}
}
buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
fmt++;
} else {
*buf++ = *fmt++;
}
}
return buf;
}
IMO writing similar stuff only causes waste of memory,your idea?
Whether it's "worth it" is subjective - there are lots of things to consider:
What advantages does it give over sprintf? Do you need them?
Are you willing to live with whatever shortcomings may be there?
Do you understand the code well enough to be able to fix it if problems are found?
Is it as fast as sprintf? If not, do you care?
You may also want to consider writing a cover function that adds whatever extra functionality you need but then just calls sprintf, rather than re-implement the entire function.
I think this kind of thing is not only wasteful but actively harmful. The name includes printf, which would lead a reasonable person first seeing code that's using it to assume its format strings are printf-compatible. But in fact they're only a very poor approximation of printf semantics. This could lead to extremely serious, security-critical bugs, which might go undetected if the code only appears in a non-common-usage case. The C standard has a perfectly safe and usable snprintf function which should always be used when this functionality is needed. And shame on whoever designed this junk in the name of "security"...