Learning C

Published at Apr 13, 2024

#embedded
#programming
#C

Compiler

We need a compiler that translates your source code into an executable program that your machine can understand. In most Linux distributions, the GCC command comes pre-installed. However, if it’s not, you can install it in Debian based distributions like Ubuntu, by running the command

sudo apt-get install gcc

There are other compilers like Clang,TinyCC,etc . I will stick with gcc as start point.

Debugger

I will also learn about GBD, more about this in another post.

Checking memory leaks?

I perceive some bad press on C due to high responsability on the software engineer to take care of memory management, leading to memory leaks problems. I found Valgrind, a tool that can help you find memory leaks , I will test it further in coming posts.

Testing

Found criterion. I used it in the usb project, and really liked it. Github Criterion Intro video

Some C syntax

I followed these guides:

/*
 *****************************
 * ***** HEADER FILES
 *****************************
 *Include necessary header files that contain declarations of functions,
 *constants, and macros that can be used in one or more source code files. Some
 *popular header files are as
 */

#include <stdio.h> //Provides input and output functions like printf and scanf

#include <stdlib.h> //Contains functions involving memory allocation, rand function, and other utility functions.

#include <math.h> //Includes mathematical functions like sqrt, sin, cos, etc.

#include <string.h> //Includes functions for manipulating strings, such as strcpy, strlen, etc.

#include <time.h> //Contains functions for working with date and time.

#include <stdbool.h> //Defines the boolean data type and values true and false.

#include <limits.h> //Defines various implementation-specific limits on integer types.

#include <ctype.h> //Contains functions for working with date and time.

/*****************************
 * ***** CONSTANTS
 *****************************/
// Constant with define (Note: 1. NO ; in endline 2. No type declaration)
#define PI_DEFINE 3.14159
// Constant with const
const float PI_CONST = 3.14159;
// What is difference defining constant both ways?
// !with #define, compiler will replace PI_DEFINE everywhere in your code with
// value 5
// !with const, wherever you use Pi_CONST it will point back to this constant
// value

/*****************************
 * ***** MACRDS
 *****************************/
// normally I would just use r*r but just to use math library
#define AREA(r) (PI_DEFINE * pow(r, 2.0))

/*****************************
 * ***** GLOBAL DECLARATION
 *****************************/
int globalB = 10; // Global declaration

int main() {
  printf("Hello world!\n"); // stdio library

  // Using constants
  float useAdef = PI_DEFINE + 1; // here PI will be replaced (LITERALLY)
  float useAconst = PI_CONST + 1;
  printf("Using constants: %f and %f\n", useAdef, useAconst);

  // Using macros
  float area = AREA(5);
  printf("Area %f\n", area);

  /*****************************
   * ***** DATA TYPES
   * Type of variable determines how much space it occupies in storage
   *****************************/

  // 1. Basic types
  // Integer and flating types ONLY
  char char1 = 100;           // 1 byte | -128 to 127 or 0 to 255
  unsigned char uchar1 = 250; // 1 byte | 0 to 255
  signed char schar1 = -125;  // 1 byte | -128 to 127

  int int1 =
      10000; // 2 or 4 bytes | -32768 to 32767 or -2147483648 to 2147483647
  unsigned int uint1 = 20000; // 2 or 4 bytes | 0 to 65535 or 0 to 4294967295

  short short1 = 1010;            // 2 bytes | -32768 to 32767
  unsigned short ushort1 = 65000; // 2 bytes | 0 to 65,535

  long long1 = 38282828;           // 8 bytes
  unsigned long ulong1 = 38282828; // 8 bytes

  // printf %lu is long unsigned
  printf("%lu\n", sizeof(ulong1)); // sizeof gets size of variable

  float float1 = 1.3;      // 4 bytes | 1.2E-38 to 3.4E+38 | 6 decimals
  double double1 = 3.3E33; // 8 bytes | 2.3E-308 to 1.7E+308 | 15 decimals
  long double ldouble1 =
      1.1E+300; // 10 byte |  3.4E-4932 to 1.1E+4932 | 19 decimals

  // 2. Enumerated types
  enum Level { LOW, MEDIUM, HIGH };
  enum Level l1 = MEDIUM;
  printf("Level enum : %d\n", l1);
  enum Level100 { LOW100 = 25, MEDIUM100 = 50, HIGH100 = 75 };
  enum Level100 l2 = MEDIUM100;
  printf("Level enum : %d\n", l2);

  // 3. Void data type
  //

  // 4. Derived types
  // Pointer, array , structure, union and function
  int x = 10;
  int *pX = &x;

  // TODO : talk about memory size, how pointer can hint your memory ram ?
  printf("Address of var x: %p\n", &x);
  printf("Address stored in pX variable: %p\n", pX);
  printf("Value of *pX variable: %d\n", *pX);

  // Declared array but uninitialized elements .It may show certain
  // random garbage values.
  int marks[5];
  for (int i = 0; i < 5; i++) {
    printf("%d ", marks[i]);
  }
  printf("\n");
  int marks2[5] = {1, 2, 3, 4, 5};
  for (int i = 0; i < 5; i++) {
    printf("%d ", marks2[i]);
  }
  printf("\n");
  int marks0[5] = {0}; // initializing to zero
  for (int i = 0; i < 5; i++) {
    printf("%d ", marks0[i]);
  }
  printf("\n");

  // size of array is the size of bytes!
  // an int has 2 or 4 bytes size(default to 4)
  printf("Size of array: %ld\n", sizeof(marks0));
  for (int i = 0; i < 5; i++) {
    printf("a[%d]: %d \t Address: %p\n", i, marks0[i], &marks0[i]);
  }

  /* The C language does not check whether array indices are in bounds, so if
   * the code uses an out-of-range index, it will access memory outside the
   * array. To be fair, this also happens with other languages as well .
   * */

  struct Student {
    char name[20];
    int marks, age;
  };

  struct Student me;

  union ab {
    int a;
    float b;
  };

  return 0;
}

Some useful links

https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/ https://ioflood.com/blog/install-gcc-command-linux/ https://valgrind.org/docs/manual/quick-start.html https://cs.brown.edu/courses/csci0300/2024/assign/labs/lab1.html