Can't understand this conversion from C to Assembly - c

I'd like to know if someone can explain me the solution to this problem:
the code is:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int c[20];
int n;
} t_coda;
t_coda coda;
void init(t_coda *coda) {
coda->n = 0;
}
void add(t_coda *coda, int x) {
if (coda->n < 20)
coda->c[(coda->n)++] = x;
}
main() {
init(&coda);
coda->n=1;
coda->c[0]=2;
add(&coda,3);
add(&coda,4);
}
And I need to know the corresponding instruction of: coda->n = 0; and coda->c[(coda->n)++] = x; in simplesem (an assembly-like semantic);
The solution is:
set D[D[0]+3]+20, 0
for the first question
and:
set D[D[0]+3]+D[D[D[0]+3]+20], D[D[0]+4]
set D[D[0]+3]+20, D[D[D[0]+3]+20] + 1
for the second one;
D is the Data stack, and D[0] return the value contained in the 0-cell of the data
Thank you

I would guess that...
D[0]+3 is a reference to the address of coda (the *coda in the function call)
D[D[0]+3] is a lookup of the data at the address where coda is stored
D[D[0]+3]+20 is an offset of 20 from where coda begins, thus moving past coda->c (which is 20 items) to get to coda->n.
That should help you to understand the first one; the same ideas can be extended to the second.

Related

memory access error when sorting struct field

i have some problems sorting a struct field and cannot find the answer why this is happening...
The Error message when i run the program says "Memory access error (German: Speicherzugriffsfehler (Speicherabzug geschrieben)). The error only comes whenever i try the proceed one of the following lines in the bubblesort:
x= *mannschaften[i];
*mannschaften[i]=*mannschaften[i+1];
*mannschaften[i+1]=x;
vertauscht=1;
I have the feeling that i might have to save memory with malloc() or calloc() at some point, but i don't know how to use this,yet...
Thank you for your help!
Best regards
kazimir
You can see the the entire code below:
#include <stdio.h>
#include <string.h>
typedef struct
{
char* nation;
int goals_scored;
int goals_conceded;
} Team;
typedef struct
{
Team* t1;
Team* t2;
int goals_t1;
int goals_t2;
}Spiel;
void ergebnis_eintragen(Spiel s)
{
s.t1->goals_scored = s.goals_t1;
s.t2->goals_scored = s.goals_t2;
s.t1->goals_conceded = s.goals_t2;
s.t2->goals_conceded = s.goals_t1;
}
void ausgabe (Team* mannschaften[8])
{
Team x;
int m=8;
int vertauscht;
do
{
vertauscht=0;
for (int i=0;i<8;i++)
{
if (mannschaften[i]->goals_scored<mannschaften[i+1]->goals_scored)
{
x= *mannschaften[i];
*mannschaften[i]=*mannschaften[i+1];
*mannschaften[i+1]=x;
vertauscht=1;
}
else if (mannschaften[i]->goals_scored==mannschaften[i+1]->goals_scored||mannschaften[i]->goals_conceded>mannschaften[i+1]->goals_conceded)
{
x = *mannschaften[i];
*mannschaften[i]=*mannschaften[i+1];
*mannschaften[i+1]=x;
vertauscht=1;
}
}
m-=1;
}
while (m>1 && vertauscht);
for (int i=0;i<8;i++)
printf("\nNation: %s\nTore: %d\nGegentore: %d\n",mannschaften[i]->nation,mannschaften[i]->goals_scored,mannschaften[i]->goals_conceded);
}
int main (void)
{
Team t1={"Kroatien",0,0};
Team t2={"Brasilien",0,0};
Team t3={"Niederlande",0,0};
Team t4={"Argentinien",0,0};
Team t5={"Marokko",0,0};
Team t6={"Portugal",0,0};
Team t7={"England",0,0};
Team t8={"Frankreich",0,0};
Spiel s1={&t1,&t2,5,3};
Spiel s2={&t3,&t4,5,6};
Spiel s3={&t5,&t6,1,0};
Spiel s4={&t7,&t8,1,2};
Spiel s5={&t4,&t1,3,0};
Spiel s6={&t8,&t5,2,0};
Spiel s7={&t1,&t5,2,1};
Spiel s8={&t4,&t8,7,5};
Team* ptr_team[8];
ptr_team[0] = &t1;
ptr_team[1] = &t2;
ptr_team[2] = &t3;
ptr_team[3] = &t4;
ptr_team[4] = &t5;
ptr_team[5] = &t6;
ptr_team[6] = &t7;
ptr_team[7] = &t8;
ergebnis_eintragen(s1);
ergebnis_eintragen(s2);
ergebnis_eintragen(s3);
ergebnis_eintragen(s4);
ergebnis_eintragen(s5);
ergebnis_eintragen(s6);
ergebnis_eintragen(s7);
ergebnis_eintragen(s8);
ausgabe(&ptr_team[0]);
}
I already tried looking for a simular question, but couldn't find anything...
In the for loop
for (int i=0;i<8;i++)
{
if (mannschaften[i]->goals_scored<mannschaften[i+1]->goals_scored)
when i is equal to 7 then expressions like this
mannschaften[i+1]->goals_scored)
access memory outside the array ptr_team defined in main.
You could write your loop like for example
for (int i=1;i<8;i++)
{
if (mannschaften[i-1]->goals_scored<mannschaften[i]->goals_scored)
//...
Also it seems in this if statement
else if (mannschaften[i]->goals_scored==mannschaften[i+1]->goals_scored||mannschaften[i]->goals_conceded>mannschaften[i+1]->goals_conceded)
you mean the logical operator && instead of the logical operator ||
else if (mannschaften[i]->goals_scored==mannschaften[i+1]->goals_scored && mannschaften[i]->goals_conceded>mannschaften[i+1]->goals_conceded)
Using the variable m as is in the do-while loop does not make a great sense. It is enough to use the variable vertauscht
do
{
//...
} while ( vertauscht);
And it is a bad idea to use magic numbers like 8.
You could declare your function like
void ausgabe (Team* mannschaften[], size_t n );
and call it at least like
ausgabe( ptr_team, 8 );
Then within the function you should use the variable n instead of the magic number 8 as for example
for ( size_t i = 1;i < n;i++ )
Otherwise you will need to change your function each time when the size of the passed array will be changed.
You should always write a more general function.
Pay attention to that your program will look much better and will be more readable if you will use English words for identifiers.

choosing between relaxed and acquire/release memory ordering in atomics

I am implementing a very simple logic. Although, I am having a tough time figuring out the memory ordering to choose.
I have a simple struct like:
typedef unsigned int bitmap;
const size_t bits_count = sizeof(bitmap) * 8;
struct Container {
_Atomic(bitmap) reader_bitmap, writer_bitmap;
int cs[bits_count];
};
cs[bits_count] is the main deal here. Multiple producers will add data to it and multiple consumers will get data from it.
To synchronise this, I have 2 bitmaps, reader_bitmap and writer_bitmap. Both of them are initially 0. What I basically do is when I want to store a value to the array, I check the bitmap if it contains any unset bit and get that bit's position. Then I set the bit atomically and using this bit position as the index, I store data in cs[bit_posn]. Then to tell readers that data is available for reading, the same bit is set in reader_bitmap.
When some thread wants to get a value from this array, it will try to unset any one bit at bit_posn from reader_bitmap and get cs[bit_posn] and then it will set the same bit in writer_bitmap to tell the produces that this position is vacant for them to write.
Here is the code for the same (minimal reproducible example, I may have missed some edge cases):
#include <stdio.h>
#include <stdatomic.h>
#include <stdbool.h>
#define UNSET_BIT(bitmap, n) (bitmap & ~((typeof(bitmap))1 << n))
#define SET_BIT(bitmap, n) (bitmap | ((typeof(bitmap))1 << n))
typedef unsigned int bitmap;
const size_t bits_count = sizeof(bitmap) * 8;
struct Container {
_Atomic(bitmap) reader_bitmap, writer_bitmap;
int cs[bits_count];
};
bool store(struct Container *cont, int data) {
bitmap old_val, new_val;
int first_unset_bit;
old_val = atomic_load_explicit(&cont->writer_bitmap, memory_order_relaxed);
do {
first_unset_bit = __builtin_ffs(~old_val) - 1;
if (first_unset_bit == -1) return false;
new_val = SET_BIT(old_val, first_unset_bit);
} while(!atomic_compare_exchange_weak_explicit(
&cont->writer_bitmap,
&old_val,
new_val,
memory_order_relaxed,
memory_order_relaxed
));
cont->cs[first_unset_bit] = data;
old_val = atomic_load_explicit(&cont->reader_bitmap, memory_order_relaxed);
do {
new_val = SET_BIT(old_val, first_unset_bit);
} while(!atomic_compare_exchange_weak_explicit(
&cont->reader_bitmap,
&old_val,
new_val,
memory_order_relaxed,
memory_order_relaxed
));
return true;
}
int load(struct Container *cont, bool *did_load_fail) {
bitmap old_val, new_val;
int first_set_bit;
int retval;
*did_load_fail = false;
old_val = atomic_load_explicit(&cont->reader_bitmap, memory_order_relaxed);
do {
first_set_bit = __builtin_ffs(old_val) - 1;
if (first_set_bit == -1) {
*did_load_fail = true;
return -1;
}
new_val = UNSET_BIT(old_val, first_set_bit);
} while(!atomic_compare_exchange_weak_explicit(
&cont->reader_bitmap,
&old_val,
new_val,
memory_order_relaxed,
memory_order_relaxed
));
retval = cont->cs[first_set_bit];
old_val = atomic_load_explicit(&cont->writer_bitmap, memory_order_relaxed);
do {
new_val = UNSET_BIT(old_val, first_set_bit);
} while(!atomic_compare_exchange_weak_explicit(
&cont->writer_bitmap,
&old_val,
new_val,
memory_order_relaxed,
memory_order_relaxed
));
return retval;
}
int main(int argc, char *argv[])
{
return 0;
}
I tried to think about memory orderings here but it seems so vague to me. I need help understanding this in actual technical terms understanding what possible cases can actually happen.
I will try to give a general description on what my theory is. It maybe totally nonsense because I am really not sure how all this is actually working behind the scenes which is why I need help.
Let's say I chose to use release ordering everywhere like I did above. In store(), first I set the writer_bitmap's bit at bit_posn and then I set reader_bitmap at bit_posn.
Is it possible for some thread to "see" this bit_posn not set in writer_bitmap but set in reader_bitmap?
Let's say it was possible (actually want to know if it is or not), and then that thread called load(), and bit_posn was found set in reader_bitmap but that thread was still unaware that same bit is also set in writer_bitmap.
It would unset that in reader_bitmap and then try to unset the same in writer_bitmap. As per this, not knowing about writer_bitmap didn't matter as at last it was synchronized anyways.
Another case that I think of is writer_bitmap has a bit set but other thread doesn't know about it? (I guess this is not possible and is handled by atomics).
I know the question is pretty long. If it's unclear anywhere, please ask in the comments.

sccz80:"../lib/main.c" L:16 Warning:#14:Expected ',' sccz80:"../lib/main.c" L:16 Error:#28:Segmentation fault

I'm getting the following error on compilation of the code below:
sccz80:"../lib/main.c" L:16 Warning:#14:Expected ','
sccz80:"../lib/main.c" L:16 Error:#28:Segmentation fault
/*
* A test game of Pong using the Z88dk
*/
#include <spectrum.h>
#include <graphics.h>
#include <sprites/sp1.h>
#include <stdio.h>
struct Bat {
int x;
int y;
int w;
int h;
};
void clear_screen(Bat* bat)
{
undrawb(bat.x, bat.y, bat.w, bat.h);
}
int main()
{
struct Bat bat;
bat.x = 0;
bat.y = 0;
bat.w = 8;
bat.h = 24;
while(1)
{
zx_border(INK_GREEN);
clear_screen(&bat);
drawb(bat.x, bat.y, bat.w, bat.h);
}
return 0;
}
Any suggestions on what might be the issue? I'm using the z88dk to create a test ZX Spectrum program. Unfortunately, I don't have a high enough score to add a 'z88dk' tag. Apologies for that.
You have 2 errors in your program:
void clear_screen(Bat* bat)
{
undrawb(bat.x, bat.y, bat.w, bat.h);
}
There is no type Bat defined in your code. Only struct Bat.
Then bat is of type "pointer to struct". This means you cannot access the struct members using . operator but you need to dereference via ->.
It is really strange that your compiler provides an error message that does not contain any of these errors but instead mentions a line (assuming L:16 indicates line 16) and some reason that do not match the code.

Timing behavior of null pointers in C

The below is mostly tested for Microsoft CL Version 17.00.50727.1 on Windows 7, but I see something similar with g++. I'm quite sure that the logical function is correct. The question is only about the timing.
Essentially I have a function that dynamically returns new "blocks" of data as needed. If it runs out of space in its "page", it makes a new page.
The purpose of the blocks is to match incoming data keys. If the key is found, that's great. If not, then a new data key is added to the block. If the block runs out of space, then a new block is created and linked to the old one.
The code works whether or not the block-making function explicitly sets the "next" pointer in the new block to NULL. The theory is that calloc() has set the content to 0 already.
The first odd thing is that the block-making function takes about 5 times(!) longer to run when that "next" pointer is explicitly set to NULL. However, then that is done, then the timing of the overall example behaves as expected: It takes linearly longer to match a new key, the more entries there are in the key list. The only difference occurs when a key is added which causes a new block to be fetched. The overhead of doing that is similar to the time taken to call the block-making function.
The only problem with this is that the block-making function is unacceptably slow then.
When the pointer is NOT explicitly set to NULL, then the block-making function becomes nice and fast -- maybe half to a quarter of the key-matching function, instead of as long or even longer.
But then the key-matching function starts to exhibit odd timing behavior. It does mostly increase linearly with the number of keys. It still has jumps at 16 and 32 keys (since the list length is 16). But it also has a large jump at key number 0, and it has large jumps at keys number 17, 33 etc.
These are the key numbers when the program first has to look at the "next" pointer. Apparently it takes a long time to figure out that the 0 value from calloc is really a NULL pointer? Once it knows this, the next times are faster.
The second weird thing is that the effect goes away if the data struct consists exclusively of the key. Now the jumps at 0, 17, 33 etc. go away whether or not the "next" pointer is explicitly set to NULL. But when "int unused[4]" is also in the struct, then the effect returns.
Maybe the compiler (with option /O2 or with -O3 for g++) optimizes away the struct when it consists of a single number? But I still don't see why that would affect the timing behavior in this way.
I've tried to simplify the example as much as I could from the real code, but I'm sorry that it's still quite long. It's not that complicated, though.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
void timer_start(int n);
void timer_end(int n);
void print_times();
// There are pages of blocks, and data entries per block.
// We don't know ahead of time how many there will be.
// GetNextBlock() returns new blocks, and if necessary
// makes new pages. MatchOrStore() goes through data in
// a block to try to match the key. It won't ever match
// in this example, so the function makes a new data entry.
struct dataType
{
// Surprise number 1: If the line with "unused" is
// commented out, things behave as expected, even if
// Surprise number 2 is in effect.
int unused[4];
int key;
};
#define DATA_PER_BLOCK 16
struct blockType
{
char nextEntryNo;
struct dataType list[DATA_PER_BLOCK];
struct blockType * next;
};
struct pageType
{
int nextBlockNo;
struct blockType * list;
struct pageType * next;
struct pageType * prev;
};
struct blockType * GetNextBlock();
void MatchOrStore(
struct dataType * dp,
struct blockType * bp);
struct pageType * pagep;
int main(int argc, char * argv[])
{
pagep = (struct pageType *) 0;
struct dataType data;
for (int j = 0; j < 50000; j++)
{
struct blockType * blockp = GetNextBlock();
// Make different keys each time.
for (data.key = 0; data.key < 40; data.key++)
{
// One timer per key number, useful for statistics.
timer_start(data.key);
MatchOrStore(&data, blockp);
timer_end(data.key);
}
}
print_times();
exit(0);
}
#define BLOCKS_PER_PAGE 5000
struct blockType * GetNextBlock()
{
if (pagep == NULL ||
pagep->nextBlockNo == BLOCKS_PER_PAGE)
{
// If this runs out of page space, it makes some more.
struct pageType * newpagep = (struct pageType *)
calloc(1, sizeof(struct pageType));
newpagep->list = (struct blockType *)
calloc(BLOCKS_PER_PAGE, sizeof(struct blockType));
// I never actually free this, but you get the idea.
newpagep->nextBlockNo = 0;
newpagep->next = NULL;
newpagep->prev = pagep;
if (pagep)
pagep->next = newpagep;
pagep = newpagep;
}
struct blockType * bp = &pagep->list[ pagep->nextBlockNo++ ];
// Surprise number 2: If this line is active, then the
// timing behaves as expected. If it is commented out,
// then presumably calloc still sets next to NULL.
// But the timing changes in an unexpected way.
// bp->next = (struct blockType *) 0;
return bp;
}
void MatchOrStore(
struct dataType * dp,
struct blockType * blockp)
{
struct blockType * bp = blockp;
while (1)
{
for (int i = 0; i < bp->nextEntryNo; i++)
{
// This will spend some time traversing the list of
// blocks, failing to find the key, because that's
// the way I've set up the data for this example.
if (bp->list[i].key != dp->key) continue;
// It will never match.
return;
}
if (! bp->next) break;
bp = bp->next;
}
if (bp->nextEntryNo == DATA_PER_BLOCK)
{
// Once in a while it will run out of space, so it
// will make a new block and add it to the list.
timer_start(99);
struct blockType * bptemp = GetNextBlock();
bp->next = bptemp;
bp = bptemp;
timer_end(99);
}
// Since it didn't find the key, it will store the key
// in the list here.
bp->list[ bp->nextEntryNo++ ].key = dp->key;
}
#define NUM_TIMERS 100
#ifdef _WIN32
#include <time.h>
LARGE_INTEGER
tu0[NUM_TIMERS],
tu1[NUM_TIMERS];
#else
#include <sys/time.h>
struct timeval
tu0[NUM_TIMERS],
tu1[NUM_TIMERS];
#endif
int ctu[NUM_TIMERS],
number[NUM_TIMERS];
void timer_start(int no)
{
number[no]++;
#ifdef _WIN32
QueryPerformanceCounter(&tu0[no]);
#else
gettimeofday(&tu0[no], NULL);
#endif
}
void timer_end(int no)
{
#ifdef _WIN32
QueryPerformanceCounter(&tu1[no]);
ctu[no] += (tu1[no].QuadPart - tu0[no].QuadPart);
#else
gettimeofday(&tu1[no], NULL);
ctu[no] += 1000000 * (tu1[no].tv_sec - tu0[no].tv_sec )
+ (tu1[no].tv_usec - tu0[no].tv_usec);
#endif
}
void print_times()
{
printf("%5s %10s %10s %8s\n",
"n", "Number", "User ticks", "Avg");
for (int n = 0; n < NUM_TIMERS; n++)
{
if (number[n] == 0)
continue;
printf("%5d %10d %10d %8.2f\n",
n,
number[n],
ctu[n],
ctu[n] / (double) number[n]);
}
}

Segmentation fault happened while calling a correct function

I am solving a 0-1knapsack problem.
I solved the problem by brute force algorithm.
In main.cpp
int main(int argc, char *argv[])
{
......
int solution;
solution = bruteForce();
......
}
The strange thing is, when I implement the bruteForce() in main.cpp, my program works correctly, however, after I move the bruteForce() to bruteForce.cpp and included it in main.cpp, the program will produce segmentation fault when calling the bruteForce().
Here's how I move bruteForce() to bruteForce.cpp.
First I created a header functions.h(because I want to solve the problem by other method after implement brute force successfully)
functions.h:
#include "global.h"
int bruteForce();
int multiplication( int );
And then I move bruteForce() to bruteForce.cpp
#include <iostream>
#include <stdlib.h>
#include <vector>
#include "global.h"
#include "functions.h"
using namespace std;
int bruteForce()
{
int bestValue = 0;
int j, tempSize, tempValue;
int bestChoice[n+1];
for(int i=0; i<multiplication(n); i++)
{
tempSize = 0;
tempValue =0;
j = n;
while(x[j]!=0 && j>0)
{
x[j] = 0;
j--;
}
x[j] = 1;
for(int k=1; k<=n; k++)
{
if(x[k] == 1)
{
tempSize += size[k];
tempValue += value[k];
}
}
if((tempValue > bestValue) && (tempSize <= S))
{
bestValue = tempValue;
for(int p=1; p<=n; p++)
bestChoice[p] = x[p];
}
}
for(int p=1; p<=n; p++)
x[p] = bestChoice[p];
return bestValue;
}
In global.h, I declared some glabal variables:
#include <vector>
using std::vector;
static int n, S;
static vector<int> value, size, x;
The gdb debugger shows
Program received signal SIGSEGV, Segmentation fault.
0x08049308 in main()
Any idea about why this happens?
Thanks in advance.
Oh BTW, if you need more info, here's the package.
You can first type make in the root of this package. Then type this to execute.
./bin/01knapsack -BF inputs/n5S11.in n5s11.out
You shouldn't put your variables in a header file. When you include that from both your source files, both will get their own individual copy of that variable - and thus you wont be able to transfer data between your functions in the way you think (or at least, that's my understanding of how it should work - I'll admit that I'm not 100% sure what actually happens).
The best way to transfer data to a function is to use parameters though. Call the function with whatever it needs, and return data either through the function return value, or through a pointer or reference parameter. Using global variables for stuff like this is error prone (as you have seen), and it's much less clear for others looking at your code.
If you absolutely want to use global variables, declare them in one of your source files, and put them in your global header file with an extern statement in front of it. When you then include the header from another file, extern tells the compiler that it shouldn't actually create the variable itself, but rather that it is provided by another object file.
So, in main.cpp:
int n, S;
vector<int> value, size, x;
And in global.h:
extern int n, S;
extern vector<int> value, size, x;

Resources