[{"content":" Steve Jobs giving graduation speech at Standford, 2005 In the tech world, it\u0026rsquo;s common to hear stories of fierce competition and bitter rivalries. One of the most famous of these is the rivalry between Apple and Microsoft. However, there is a lesser-known story about how Microsoft actually helped save Apple from financial ruin.\nIn 1997, Apple was struggling and had no clear direction. The company had just acquired NeXT computers, which laid the foundation for their future operating system, MacOS. Steve Jobs, who had previously been fired from Apple, returned as the interim CEO and set out to clean up the company. He knew that Apple needed partners and capital injection to survive and avoid laying off talented people.\nBill Gates at MacWorld, 1997 At the same time, Microsoft was the undisputed leader in the PC market with over 90% market share. Apple and Microsoft were in patent infringement negotiations[1] that were leading to frustration on both sides. Jobs went to Bill Gates and negotiated a deal where Microsoft would invest $150 million in Apple, guarantee support for Microsoft Office on MacOS for the next 5 years, and drop a patent infringement lawsuit. It led to the famous Apple event where Bill Gates appeared as the towering image above Steve Jobs on the stage, much to everyone\u0026rsquo;s dismay because Microsoft stood for everything that they hated about consumer software.\nThis deal was a pivotal moment in tech history that saved Apple from financial ruin. Without it, Apple may not have survived as a company. From Microsoft\u0026rsquo;s point of view, it was a small price to pay for avoiding a potentially expensive lawsuit. It allowed Apple to survive and ultimately revolutionize personal computing with the introduction of the iPhone and rest is history.\nSo, the next time you\u0026rsquo;re using an Apple product, take a moment to thank Microsoft for their role in saving the company and changing the course of history.\nThis interesting nugget of history is from book Becoming Steve Jobs. Good read.\n[1] https://en.wikipedia.org/wiki/Apple_Computer,_Inc._v._Microsoft_Corp\n","date":"2023-08-13T15:55:35Z","image":"https://jiten-thakkar.com/images/blog/microsoft-apple-1997.jpg","permalink":"https://jiten-thakkar.com/posts/2023-08-13-how-microsoft-saved-apple-and-accidentally-revolutionized-personal-computing/","title":"How Microsoft Saved Apple and Accidentally Revolutionized Personal Computing"},{"content":"I have been biking a lot on east coast Greenway biking trails lately. It\u0026rsquo;s a network of trails spread out across suburbs of Durham, Raleigh and Cary in the Triangle Research Area in North Carolina. It has off-road routes dedicated to bikers and pedestrians. You can feel immersed in the beautiful surroundings along creeks and rivers without the fear of the traffic.\nSome interesting facts about the Greenway:\nThe idea of a greenway linking existing and planned trails into a contiguous \u0026ldquo;spline route\u0026rdquo; between Atlantic coast cities was conceived by a group of cyclists and long-distance trail enthusiasts in NYC in 1991 and East Coast Greenway Alliance (ECGA) was formed. Neuse River, NC The first five segment was designed in 1996 in the Baltimore \u0026amp; Annapolis Trail in Maryland, the Charter Oak Greenway in Connecticut, the Coventry Greenway in Rhode Island, the Farmington Canal Greenway in Connecticut, and the Delaware \u0026amp; Raritan Canal Trail in New Jersey totaling 56 miles. Crabtree Creek Trail, Raleigh, NC Crabtree Creek Trail, Raleigh, NC Within next 4 years a whopping 150 miles of trail segments were added to the network. Today the Greenway has pedestrian and bicycle route reaching 3000 miles from Maine to Florida along the East Coast of the United States of which 1000 miles of the route if off-road. It\u0026rsquo;s remarkable how something started by a small group of passionate people grew into a national phenomenon touching lives of millions.\n","date":"2023-05-04T05:33:53Z","image":"https://jiten-thakkar.com/images/blog/east-coast-greenway.jpg","permalink":"https://jiten-thakkar.com/posts/2023-05-04-east-coast-greenway/","title":"East Coast Greenway"},{"content":"Strongly typed programming languages like Java, C++, C#, etc. has great benefits because of its typed nature. Forcing the users to define the type of entity upfront allows the programming language to provide type safety guarantees. Strong typing has its own advantages, and a whole blog post can be written on it. Some of the essential gains are early-type error detection, compile-time optimization, documentation, etc. But this advantage can also be constraining in writing generic, type agnostic, reusable code if not supported correctly. That is precisely why these languages usually allow writing generically typed entities. For example, in Java it\u0026rsquo;s called generics, in C++ it\u0026rsquo;s called templates and parametric polymorphism in Haskell and so on. This style of programming is called Generic Programming. In this style of programming, programs are written with types that are to be defined later by providing type as a parameter when initiated. Every language has it\u0026rsquo;s own way of implementing and supporting generic types. In this blog post, we will look at how Java does it under the hood.\nDuring compilation, Java compiler replaces erasure type with type Object if the generic type is unbounded. For example:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Test\u0026lt;T\u0026gt; { private final T a; public Test(T a) { this.a = a; } public T getA() { return a; } } converts into this after compilation:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Test { private final Object a; public Test(Object a) { this.a = a; } public Object getA() { return a; } } This is called type erasure. After compilation, JVM has no knowledge about the actual type of the generic type. That\u0026rsquo;s why you might see some type mismatch errors while dealing with generic type classes. Take this as an example:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Test\u0026lt;T\u0026gt; { private T a; public Test(T a) { this.a = a; } public T getA() { return a; } public void setA(T a) { this.a = a; } } public class MyTest extends Test\u0026lt;Integer\u0026gt; { public MyTest(Integer a) { super(a); } public void setA(Integer a) { super.setA(a); } } public class Main { public static void main(String[] args) { Test t = new MyTest(10); int a = t.getA() + 10; //Error: Operator \u0026#39;+\u0026#39; cannot be applied to \u0026#39;java.lang.Object\u0026#39;,\u0026#39;int\u0026#39; } } In the code above, we get a type mismatch error because the compiler thinks the type of field a inside Test class is Object as a result of type erasure. The way to fix this is by typecasting t.getA() with Integer. So the code becomes this\n1 2 3 4 5 6 7 public class Main { public static void main(String[] args) { Test t = new MyTest(10); int a = (Integer)t.getA() + 10; //No error } } and we don\u0026rsquo;t see any errors.\nType erasure can also lead to some interesting problems. For example, after type erasure the code above turns into this:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Test { private Object a; public Test(T a) { this.a = a; } public Object getA() { return a; } public void setA(T a) { this.a = a; } } public class MyTest extends Test { public MyTest(Integer a) { super(a); } public void setA(Integer a) { super.setA(a); } } As you can see, class myTest is no longer overriding the setA method that it intended to. To maintain the polymorphism of the generic types, the compiler introduces something called a Bridge Method. It works like this:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Test { private Object a; public Test(T a) { this.a = a; } public Object getA() { return a; } public void setA(T a) { this.a = a; } } public class MyTest extends Test { public MyTest(Integer a) { super(a); } **// Bridge method generated by the compiler public void setA(Object a) { setA((Integer)a); }** public void setA(Integer a) { super.setA(a); } } You can verify the existence of this bridge method by printing the type of parameters using java reflection.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.lang.reflect.Method; public class Main { public static void main(String[] args) { try { // create class object Class classobj = MyTest.class; // get list of methods Method[] methods = classobj.getMethods(); // get the name of every method present in the list for (Method method : methods) { String methodName = method.getName(); if (methodName.equals(\u0026#34;setA\u0026#34;)) { System.out.println(\u0026#34;Class \u0026#34; + classobj.getName() +\u0026#34; Contains\u0026#34; + \u0026#34; Method whose name is \u0026#34; + methodName); System.out.println(\u0026#34;This method has parameters whose types are:\u0026#34;); for(Class c : method.getParameterTypes()) { System.out.println(c.getName()); } System.out.println(); } } } catch (Exception e) { e.printStackTrace(); } } } The output looks like this:\n1 2 3 4 5 6 7 Class MyTest Contains Method whose name is setA This method has parameters whose types are: java.lang.Integer Class MyTest Contains Method whose name is setA This method has parameters whose types are: java.lang.Object So that\u0026rsquo;s how Java handles generic types under the hood. There are some other restrictions on Java generics that you can learn more about from here.\nAll the code in this post is available on my github profile.\n","date":"2020-05-30T14:30:00Z","image":"https://jiten-thakkar.com/images/blog/java-generics-code.jpg","permalink":"https://jiten-thakkar.com/posts/2020-05-30-java-generics-and-type-erasure/","title":"Java Generics And Type Erasure"},{"content":"The thrill of skiing is captivating. Rolling down the slopes taming the steep mountain slopes will be on top of any thrill seeker\u0026rsquo;s list. And of course the views of mountains covered in white blanket are just unbeatable.\nI haven’t always felt this way about skiing. I still remember the first time I went skiing. It was horrible. It was too tiring. I kept falling from the skis and those heavy ski boots don’t make it easy to get back on the ski. But with every ski trip my skill level and my love for skiing just grew. Now I can’t get enough of it. There are a lot of things that I wish I knew before I started skiing that could have helped me prepare better mentally and physically. In this blog I am going to put together how to prepare and what to expect in your first ski trip.\nKirwood Ski Resort, CA What To bring for skiing\nSkiing can be an expensive sport. It requires a lot of equipments to keep you safe in the harsh and cold environment. You are going to need following equipments for skiing. This is in no way an exhaustive list.\nSkis and Poles Ski boots Helmet Ski pants A waterproof ski jacket. The more layers the better. Ski Gloves. I would recommend buying gloves with loops at the end. They come in handy when you want to take them off to grab something form pocket or hold your phone. They will hang on your wrist thanks to the loops. I would also recommend buying gloves with glove liners. It helps with really cold condition. Gloves these days also come with resistive touch so that you don’t have to take them off for operating your touch screen phone. Paying attention to these small details while choosing gloves will be very useful on the slopes. Burton gloves are my favorite. Ski goggles. Spherical goggles are really good and they don’t block your side view but non spherical ones work just fine. I use these not spherical ones. Balaclava (Recommended but not necessary) They will cover your neck and protects against cold winds. It will also prevent snow from slipping in your shirt when you fall. Trust me on this one. You will thank me later. Thermal pants and shirt. This one is highly recommended but depends on your tolerance of cold. Ski socks (Recommended but not necessary) These are the knee long nylon socks that adds to the comfort Resorts usually provide rental service for skis, poles, ski boots and helmet. They usually don’t rent ski clothes. You should either rent or buy them in advanced. The Ski Renter in Mountain View is my favorite place for ski rentals. {: .text-justify}\nIf this is your first time skiing than most likely you are going to go for a ski lesson as you should. You won’t master the skill of skiing in those two hours of lessons but it will get you started on the path of learning. Learning skiing is like learning swimming or biking. The more you practice the better you get. Some resorts have ski lesson packages which include ski rental and one day of lift pass. If you are planning on going around lake Tahoe in northern California, Homewood Mountain Resort has one of the cheapest ski lesson packages that I know.\nKirwood Ski Resort, CA Ski Slope Levels\nSki slopes in ski resorts are marked with difficulty levels and they are called Piste. There are 4 major slope levels. They are decided based on slope gradients including other factors.\nGreen Circle - Green slopes are beginner slopes. They are not very steep and usually they are wide to allow wider turns for beginners. Blue Square - Intermediate slopes and are steeper than green slopes Black Diamond - They are one of the most difficult slopes on the mountain. You shouldn’t go on these slopes until you are very comfortable on blue slopes. Double Black Diamond - These will be the most difficult slopes on the mountain with additional challenges like narrower path, trees on the slope, ungroomed etc. Moguls are also marked as double diamond slopes. Park City Ski Resort, UT What to Expect in Ski Lessons\nSkiing is all about managing your speed. Once you learn to handle speed comfortably, you will enjoy skiing. In the ski lessons, you will be mostly skiing on the green slopes. The instructors usually start by teaching you how to apply breaks. Edges of the ski act like your breaks. The most basic style of controlling your speed and turns is Pizza turns. As you feel comfortable with breaking the next step in learning is making turns. When you are skiing down the slope taking S shaped turns will help you pace your speed. This is a very fundamental technique in slope skiing. The wider the S curves the more you will slow down. And as you become better, taking narrower S turns will help you skiing on steeper slopes. Remember that the Pizza turns are just to get you started on the slopes. You won’t be able to use them on steeper slopes. That’s when more advanced techniques like Parallel Turn and Pole Planting come into picture. But don’t worry about them for now. Once you feel comfortable with the initial techniques try to transition to parallel turns to become advanced skier. Don’t worry if you keep falling and getting off balance in the beginning. It’s part of the process and the key to learning is keep practicing. Happy Skiing!\nFrom learning ski and boot configurations to different advanced ski techniques, there are more topics than I can cover in one blog post. But as you practice more and more keep looking for that knowledge on YouTube or blog posts. It’s a really fun sport learn. But be careful on the slopes. Remember, it’s better to fall voluntarily than loosing control of your speed and end up breaking your limbs. Stay safe and Happy Skiing!\n","date":"2019-02-02T17:00:00Z","image":"https://jiten-thakkar.com/images/blog/skiing-mountain-resort.jpg","permalink":"https://jiten-thakkar.com/posts/2019-02-02-skiing-101/","title":"Skiing 101"},{"content":"This is a small post to demonstrate working code for writng and reading metadata information from LLVM IR. I couldn\u0026rsquo;t find any good one stop source about how to write metadata to LLVM IR. Hence this post. Metadata API was introduced to LLVM IR in LLVM-2.7 (refer to this post). Metadata information can be used to insert any kind of data related to code without any side-effects. It can be anything from debug information to any statistical data to some useless rant about how your day job sucks. For more information about them refer to the blog post in the link above. Now let\u0026rsquo;s see some code. All of these examples are written with LLVM-3.8.\nInserting Metadata\nLet\u0026rsquo;s write a function pass that inserts total number of instructions as integer to metadata of the function and order number of instruction in the function to the instruction metadata as a string (just to demonstrate how to insert string as metadata).\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 virtual bool runOnFunction(Function \u0026amp;F) { errs() \u0026lt;\u0026lt; \u0026#34;I saw a function called \u0026#34; \u0026lt;\u0026lt; F.getName() \u0026lt;\u0026lt; \u0026#34;!\\n\u0026#34;; LLVMContext\u0026amp; C = F.getContext(); int instructions = 0; if (!F.isDeclaration()) { for (auto I = inst_begin(F), E = inst_end(F); I != E; ++I) { instructions++; MDNode* N = MDNode::get(C, MDString::get(C, std::to_string(instructions))); (*I).setMetadata(\u0026#34;stats.instNumber\u0026#34;, N); } MDNode* temp_N = MDNode::get(C, ConstantAsMetadata::get(ConstantInt::get(C, llvm::APInt(64, instructions, false)))); MDNode* N = MDNode::get(C, temp_N); F.setMetadata(\u0026#34;stats.totalInsts\u0026#34;, N); } return true; } I think the code is pretty self explanatory. Important parts are setMetadata calls for instruction and function. It takes a string which represents the kind of the metadata and the metadata node which has the information. Here is the whole code.\nReading Metadata\nReading metadata is very straight forward. Just use getAllMetadata to grab all metadata nodes or use getMetadata(StringRef Kind) to access a specific metadata node. Here is full code.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 virtual bool runOnFunction(Function \u0026amp;F) { LLVMContext\u0026amp; C = F.getContext(); SmallVector\u0026lt;std::pair\u0026lt;unsigned, MDNode *\u0026gt;, 4\u0026gt; MDs; F.getAllMetadata(MDs); for (auto \u0026amp;MD : MDs) { if (MDNode *N = MD.second) { Constant* val = dyn_cast\u0026lt;ConstantAsMetadata\u0026gt;(dyn_cast\u0026lt;MDNode\u0026gt;(N-\u0026gt;getOperand(0))-\u0026gt;getOperand(0))-\u0026gt;getValue(); errs() \u0026lt;\u0026lt; \u0026#34;Total instructions in function \u0026#34; \u0026lt;\u0026lt; F.getName() \u0026lt;\u0026lt; \u0026#34; - \u0026#34; \u0026lt;\u0026lt; cast\u0026lt;ConstantInt\u0026gt;(val)-\u0026gt;getSExtValue() \u0026lt;\u0026lt; \u0026#34;\\n\u0026#34;; } } for(auto I = inst_begin(F), E = inst_end(F); I != E; ++I) { //showing different way of accessing metadata if (MDNode* N = (*I).getMetadata(\u0026#34;stats.instNumber\u0026#34;)) { errs() \u0026lt;\u0026lt; cast\u0026lt;MDString\u0026gt;(N-\u0026gt;getOperand(0))-\u0026gt;getString() \u0026lt;\u0026lt; \u0026#34;\\n\u0026#34;; } } return false; } ","date":"2017-05-29T19:20:00Z","image":"https://jiten-thakkar.com/images/blog/llvm-compiler.jpg","permalink":"https://jiten-thakkar.com/posts/2017-05-29-how-to-read-and-write-metadata-in-llvm/","title":"How to Read and Write Metadata in LLVM"},{"content":"Object oriented languages like C++, Java etc usually support generic programming (templates in C++ and generics in Java). So it becomes easy to write a generic library in those languages. For a language like C, it is slightly complicated to write such library because it doesn’t have concept of classes and doesn’t support generic programming right off the bat. But not to worry. It’s doable. It just requires some knowledge of heap memory and magical powers of void pointers. So let’s design a generic stack.\nFirst, let’s define a structure which would have the data of the stack and all the book keeping information like reference to last element and total elements.\nStack { data ==\u0026gt; field that holds all the data topElement ==\u0026gt; field that point to the top member totalCapacity ==\u0026gt; total capacity of the stack, useful to check is the stack is full or not } The data field here needs to support any type of data (basic and user defined) for which we want to make a stack. Here the void pointers come into picture. Before we go into how void pointer would be used, let’s understand how memory access in C works from the point of view of types.\nWhen you declare a pointer like int *a in C, it just says that the data pointed to by the pointer is of type integer. This information is used by the compiler when the code accesses the data in that memory location. It tells the compiler how many bytes of data needs to be read while accessing the memory pointed to by a pointer of type int. Suppose size of an integer is 4 bytes, then it will read 4 bytes of data while accessing the pointer. This tells us that regardless of the type of data that is stored at the destination, the number of bytes that are read relies on the type of the pointer that points to that location. So if we typecast the same pointer that was pointing to a to double*, then it would now read 8 bytes of data when accessed(assuming that double is of 8 bytes in the system). When you access data using a void pointer, the compiler gives an error because it doesn’t know how much data needs to be read because there is no type. But if you typecast the same void pointer to an integer then it would treat the underlying data as an integer and if you typecast it to a double then it would treat the data as double.\nWell, that’s where the trick lies for writing a generic data structure in C. Disguise the data as void when storing them and when you want to read it, just read the necessary number of bytes based on the type of the data that is being stored. Based on the above explaination, we can now define the data structure for stack as follow:\ntypedef struct { void* data; int top; int totalElements; int memberSize; } Stack; Here, first three members are as explained in the structure above. The data field is declared as void* so that it can point to any type of data. The fourth member memberSize has the size in number of bytes of one member of the type for which we are writing the Stack. As explained, we will use this field about member size while accessing the data stored in data field. So to conclude, the Stack which is represented as a structure consists of memberSize to know the size of an element store in the data, totalElements to know the total capacity of the Stack and top which tells the index of the member that is on the top of the stack.\nNow that we have figured out the structure of the generic Stack, let’s write the functionalities for the stack. We will write function create stack, push, top, pop and destroy.\nFirst createStack. This one is straight forward. The function will take initial size of the Stack and size of the member element. We will use these two to calculate total memory required for the stack and allocate it. We will initialize top to -1 which means the stack is empty. So, the function would be something like this:\nStack* createStack(int memberSize, int totalElements) { Stack *s = malloc(sizeof(Stack)); s-\u0026gt;top = -1; s-\u0026gt;memberSize = memberSize; s-\u0026gt;totalElements = totalElements; s-\u0026gt;data = malloc(totalElements*memberSize); return s; } We are allocating total of totalElements*memberSize bytes of data for the stack using malloc function. This means if we are creating a stack of size 10 for type int, then assuming the size of int is 4 bytes, we will allocate 40 bytes of data for the stack. You can think of field data as an array of 40 elements of one byte each. Now, depending on how we access this data would define how to treat these 40 bytes. If we typecast the data field to int* then the compiler would treat it as an array of 10 integers. So if we do something like int* x = \u0026amp;(int*)s-\u0026gt;data[1] then pointer x would point to the 5th byte of the data array(since arrays in C start with index 0 so accessing [1] means accessing second element). Whereas if we type cast it to char* (and assuming size of char is 1 byte), the compiler would treat it as an array of 40 elements. And char* x = \u0026amp;(char*)s-\u0026gt;data[1] would point to second byte of the data array. It’s just a game of pointer arithmetics. Pretty fucked up huh! They don’t call C type unsafe for no reason.\nNext, stackPush: this is important one. Here we will use all the pointer magic to save data being pushed to the stack. Let’s walk through the code below:\nint stackPush(Stack *s, void *element) { //check is the stack is full if (s-\u0026gt;top == s-\u0026gt;totalElements - 1) { //if full, return 1 which would signal that the operation failed return 1; } s-\u0026gt;top++; //calculate starting location for the new element void* target = (char*)s-\u0026gt;data+(s-\u0026gt;top*s-\u0026gt;memberSize); memcpy(target, element, s-\u0026gt;memberSize); return 0; } Here, the data parameter contains the data that needs to be pushed to the stack. First we check if the stack if full. If it’s full then we just return 1 which would tell the caller that the call to push failed. (Later we will fix this by dynamically expanding the capacity of the stack). Now, we need to copy the data in the element parameter to the array in the Stack. For that we calculate the start index of the next member by first typecasting it to char* and then adding total bytes taken by members already in the stack. By typecasting data to char*, we are treating the data as an array of elements of size 1. This way the arithmetic to calculate target index using memberSize works out well. Lastly we copy memberSize bytes of the data into the data array using memcpy.\nWe are returning 1 whenever the stack becomes full. If you have used a generic container library like Stack in any other language, you would have noticed that you don’t have to worry about the capacity of the container. So, what if we just expand the capacity of the stack dynamically when we run out of memory? That would be cool. And doing that is also very easy thanks to realloc. This function takes pointer to the memory that was allocated dynamically and new size and expands the size of the allocated memory. Under the hood, it calls malloc to allocate memory of new size and calls memcpy to copy data from old location to the new location and returns the pointer to the new location (hey, may be you can write your own very simple realloc). Let’s write function expandStack:\nint expandStack(Stack* s) { //double total capacity of the stack s-\u0026gt;data = realloc(s-\u0026gt;data, s-\u0026gt;totalElements * 2); s-\u0026gt;totalElements *= 2; return 0; } int stackPush(Stack *s, void *data) { //check is the stack is full if (s-\u0026gt;top == s-\u0026gt;totalElements - 1) { //if full, call expand function to expand the size of the stack expandStack(s); } s-\u0026gt;top++; //calculate starting location for the new element void* target = (char*)s-\u0026gt;data+(s-\u0026gt;top*s-\u0026gt;memberSize); memcpy(target, data, s-\u0026gt;memberSize); return 0; } We will just double the size of the stack whenever we hit the capacity. And we have our stack with unlimited capacity(unlimited in theory of course).\nNext, stackPop: This function is same as stackPush just in reverse direction. Here we first check if the stack is empty. If it is then we return 1 which would tell the caller that the operation failed because the stack is empty. Else we will calculate the start index of the top element and copy that data to target pointer being passed as parameter. Here is the function:\nint stackPop(Stack *s, void *target) { if (s-\u0026gt;top == -1) { return 1; } void* source = (char*)s-\u0026gt;data+(s-\u0026gt;top*s-\u0026gt;memberSize); s-\u0026gt;top--; memcpy(target, source, s-\u0026gt;memberSize); return 0; } Next, stackTop: exactly same as stackPop function. The only difference is that we won’t reduce the top index value because we are just reading the top member. Here is the function:\nint stackTop(Stack *s, void *target) { if (s-\u0026gt;top == -1) { return 1; } void* source = (char*)s-\u0026gt;data+(s-\u0026gt;top*s-\u0026gt;memberSize); memcpy(target, source, s-\u0026gt;memberSize); return 0; } Next stackDestroy: this one is also straight forward. Free all the dynamically allocated memory and you are done. Here is the function:\nint stackDestroy(Stack *s) { free(s-\u0026gt;data); free(s); return 0; } Cool, we just made our a generic stack with some basic functionality. You can write other generic containers like queue, vectors etc. using same technique. You can checkout full code here which has additional functionality of getMax using function pointer.\n","date":"2017-03-10T08:20:00Z","image":"https://jiten-thakkar.com/images/blog/c-programming-stack.jpg","permalink":"https://jiten-thakkar.com/posts/2017-03-10-writing-generic-stack-in-c/","title":"Writing Generic stack in C"}]