Podcast
Questions and Answers
Given the function createCard(char* fileName, Card** newCardObject)
, and assuming Card
is a structure, what is the most critical reason for passing newCardObject
as a double pointer rather than a single pointer Card* newCardObject
?
Given the function createCard(char* fileName, Card** newCardObject)
, and assuming Card
is a structure, what is the most critical reason for passing newCardObject
as a double pointer rather than a single pointer Card* newCardObject
?
- To ensure that the modifications made to the `Card` structure within `createCard` are visible in the calling function, directly updating the pointer's address. (correct)
- To comply with strict ANSI C pointer arithmetic rules, which mandate that all dynamically allocated structures must be returned via double pointers.
- To avoid potential memory leaks by allowing the `createCard` function to directly deallocate and reallocate `newCardObject` if necessary.
- To optimize memory usage by preventing the creation of a copy of the `Card` pointer within the `createCard` function's scope.
Consider the following function void allocate(int* p, int len){ p = malloc(sizeof(int)*len); }
called as allocate(array, arrLen);
where int* array = NULL;
. After the function call, what is the state of array
and the allocated memory?
Consider the following function void allocate(int* p, int len){ p = malloc(sizeof(int)*len); }
called as allocate(array, arrLen);
where int* array = NULL;
. After the function call, what is the state of array
and the allocated memory?
- `array` contains garbage data, the allocated memory is pointed to by `p` within the function's scope, which is automatically freed upon function return.
- `array` remains `NULL` and the allocated memory block is automatically deallocated when the function returns, preventing any memory leaks.
- `array` remains `NULL`, the allocated memory block exists but is unreachable, resulting in a memory leak. (correct)
- `array` points to the newly allocated memory, and any previous value of `array` is lost.
In the context of using Valgrind for memory debugging, what is the significance of compiling a C program with the -g
flag, and why is it crucial for effective leak detection?
In the context of using Valgrind for memory debugging, what is the significance of compiling a C program with the -g
flag, and why is it crucial for effective leak detection?
- The `-g` flag includes debugging symbols in the compiled executable, allowing Valgrind to provide source code line numbers for memory errors, facilitating easier debugging. (correct)
- The `-g` flag automatically links the program with Valgrind's internal memory management routines, ensuring compatibility and comprehensive error reporting.
- The `-g` flag enables Valgrind to bypass certain memory protection mechanisms, providing a more accurate assessment of memory usage patterns.
- The `-g` flag optimizes the compiled binary for faster execution within the Valgrind environment, reducing the overhead of memory checks.
If Valgrind reports a "still reachable" memory block at program termination, what does this usually indicate about the program's memory management, and what are the potential implications?
If Valgrind reports a "still reachable" memory block at program termination, what does this usually indicate about the program's memory management, and what are the potential implications?
Consider a complex system where a custom memory allocator is implemented to optimize performance for specific data structures. When using Valgrind to analyze this system, which strategy would provide the most accurate and detailed insights into memory-related issues within the custom allocator?
Consider a complex system where a custom memory allocator is implemented to optimize performance for specific data structures. When using Valgrind to analyze this system, which strategy would provide the most accurate and detailed insights into memory-related issues within the custom allocator?
Considering the evolution of build automation tools, conjecture the most critical deficiency in make
that spurred the development of tools like cmake
, focusing on aspects beyond mere language support or syntactic improvements.
Considering the evolution of build automation tools, conjecture the most critical deficiency in make
that spurred the development of tools like cmake
, focusing on aspects beyond mere language support or syntactic improvements.
Given a scenario where a complex software project relies heavily on make
for its build process, and developers are observing intermittent, irreproducible build failures, which of the following root causes is the MOST likely contributor, assuming the makefiles themselves are syntactically correct?
Given a scenario where a complex software project relies heavily on make
for its build process, and developers are observing intermittent, irreproducible build failures, which of the following root causes is the MOST likely contributor, assuming the makefiles themselves are syntactically correct?
In the context of a software project employing make
for build automation, devise a scenario wherein employing a custom command that reports the 'status of the project' introduces a latent vulnerability, despite not directly altering any source code or build artifacts.
In the context of a software project employing make
for build automation, devise a scenario wherein employing a custom command that reports the 'status of the project' introduces a latent vulnerability, despite not directly altering any source code or build artifacts.
You are tasked with refactoring a legacy build system that excessively utilizes shell commands directly within makefiles
. What is the most compelling motivation for migrating these shell commands into dedicated, version-controlled scripts, beyond mere readability or maintainability improvements?
You are tasked with refactoring a legacy build system that excessively utilizes shell commands directly within makefiles
. What is the most compelling motivation for migrating these shell commands into dedicated, version-controlled scripts, beyond mere readability or maintainability improvements?
A software engineering team decides to adopt a build system that diverges from the conventional make
utility. Analyze the ramifications if this new system lacks the capability to accurately track file timestamps for dependency resolution, especially in a distributed development environment.
A software engineering team decides to adopt a build system that diverges from the conventional make
utility. Analyze the ramifications if this new system lacks the capability to accurately track file timestamps for dependency resolution, especially in a distributed development environment.
In the context of continuous integration and continuous deployment (CI/CD) pipelines, evaluate the potential security implications of using make
to manage the deployment phase, considering make
's historical design assumptions and operational characteristics.
In the context of continuous integration and continuous deployment (CI/CD) pipelines, evaluate the potential security implications of using make
to manage the deployment phase, considering make
's historical design assumptions and operational characteristics.
Assume a scenario where a software build process orchestrated by make
involves generating documentation from source code using a tool that is both memory-intensive and prone to occasional non-deterministic failures. Deduce the MOST effective strategy to mitigate the impact of these failures on the overall build process, without modifying the documentation generation tool itself.
Assume a scenario where a software build process orchestrated by make
involves generating documentation from source code using a tool that is both memory-intensive and prone to occasional non-deterministic failures. Deduce the MOST effective strategy to mitigate the impact of these failures on the overall build process, without modifying the documentation generation tool itself.
Considering the evolution from make
to more sophisticated build systems like Bazel, what fundamental shift in dependency management strategy most significantly contributes to Bazel's ability to achieve hermetic builds and improve build reproducibility, especially in polyglot projects?
Considering the evolution from make
to more sophisticated build systems like Bazel, what fundamental shift in dependency management strategy most significantly contributes to Bazel's ability to achieve hermetic builds and improve build reproducibility, especially in polyglot projects?
Within a makefile
, if a target such as clean
lacks explicit dependencies, under what specific circumstances will its associated commands be executed?
Within a makefile
, if a target such as clean
lacks explicit dependencies, under what specific circumstances will its associated commands be executed?
In the context of a complex makefile
involving multiple targets and intricate dependencies, what is the most precise and reliable method to ascertain the exact sequence of commands that make
will execute for a particular target without altering the system state?
In the context of a complex makefile
involving multiple targets and intricate dependencies, what is the most precise and reliable method to ascertain the exact sequence of commands that make
will execute for a particular target without altering the system state?
Considering portability and compatibility across diverse make
implementations, which of the following approaches represents the most robust and universally applicable method for defining multi-line commands within a makefile
?
Considering portability and compatibility across diverse make
implementations, which of the following approaches represents the most robust and universally applicable method for defining multi-line commands within a makefile
?
Within a makefile
, under what precise conditions is it most advantageous to employ macros, and what potential drawbacks should be carefully considered when extensively utilizing them?
Within a makefile
, under what precise conditions is it most advantageous to employ macros, and what potential drawbacks should be carefully considered when extensively utilizing them?
Given a makefile
containing the following macro definition: LIB_PATH = /opt/special/lib
, and a target definition: myprog: myprog.c
, what is the most reliable method to ensure that myprog
is linked against libraries located in /opt/special/lib
?
Given a makefile
containing the following macro definition: LIB_PATH = /opt/special/lib
, and a target definition: myprog: myprog.c
, what is the most reliable method to ensure that myprog
is linked against libraries located in /opt/special/lib
?
In a scenario where a makefile
macro CC
is defined as CC = clang
, but the system's default compiler is gcc
, elucidate the precise mechanism by which make
determines which compiler to utilize for the compilation process.
In a scenario where a makefile
macro CC
is defined as CC = clang
, but the system's default compiler is gcc
, elucidate the precise mechanism by which make
determines which compiler to utilize for the compilation process.
Considering a complex makefile
structure involving multiple targets, macros, and conditional statements, what is the most effective strategy for systematically debugging build failures and ensuring the correctness of the build process?
Considering a complex makefile
structure involving multiple targets, macros, and conditional statements, what is the most effective strategy for systematically debugging build failures and ensuring the correctness of the build process?
Assuming a makefile
defines a macro SRC_FILES = a.c b.c c.c
, and a target myprog
depends on these source files. How can you most elegantly ensure that every .c
file in SRC_FILES
is compiled into a corresponding .o
file, and that these .o
files are then linked to create myprog
, without explicitly listing each object file in the makefile
?
Assuming a makefile
defines a macro SRC_FILES = a.c b.c c.c
, and a target myprog
depends on these source files. How can you most elegantly ensure that every .c
file in SRC_FILES
is compiled into a corresponding .o
file, and that these .o
files are then linked to create myprog
, without explicitly listing each object file in the makefile
?
Within the context of make
utility, what constitutes the most critical distinction between prerequisites and targets in directing the build process?
Within the context of make
utility, what constitutes the most critical distinction between prerequisites and targets in directing the build process?
Consider a scenario where a complex software project is managed using make
. A core header file, common.h
, is included by nearly every source file. If common.h
is modified, what mechanism does make
employ to minimize recompilation, and what potential limitation exists?
Consider a scenario where a complex software project is managed using make
. A core header file, common.h
, is included by nearly every source file. If common.h
is modified, what mechanism does make
employ to minimize recompilation, and what potential limitation exists?
What is the most critical and often overlooked requirement when specifying command lines within a Makefile, and what consequences arise from its incorrect usage?
What is the most critical and often overlooked requirement when specifying command lines within a Makefile, and what consequences arise from its incorrect usage?
Given a Makefile with multiple targets but lacking an explicitly specified default target, how does make
determine which target to build when invoked without arguments, and what pragmatic implication does this have for project maintainability?
Given a Makefile with multiple targets but lacking an explicitly specified default target, how does make
determine which target to build when invoked without arguments, and what pragmatic implication does this have for project maintainability?
In the esoteric realm of Makefile semantics, what is the precise implication of a target lacking any associated command lines, and how does this affect the make
utility's evaluation of its prerequisites?
In the esoteric realm of Makefile semantics, what is the precise implication of a target lacking any associated command lines, and how does this affect the make
utility's evaluation of its prerequisites?
Under what highly specialized circumstances would omitting the command line associated with a target in a Makefile be strategically advantageous, and what intricate considerations govern its proper implementation?
Under what highly specialized circumstances would omitting the command line associated with a target in a Makefile be strategically advantageous, and what intricate considerations govern its proper implementation?
In the advanced usage of make
, what subtle distinction differentiates the behavior of make target
from merely invoking the commands listed under target
directly in the shell, particularly when the commands involve file operations and conditional logic?
In the advanced usage of make
, what subtle distinction differentiates the behavior of make target
from merely invoking the commands listed under target
directly in the shell, particularly when the commands involve file operations and conditional logic?
Within a large-scale software project employing make
, devise a scenario where the deliberate introduction of circular dependencies within the Makefile would be strategically advantageous, and elucidate the potential risks and mitigation strategies.
Within a large-scale software project employing make
, devise a scenario where the deliberate introduction of circular dependencies within the Makefile would be strategically advantageous, and elucidate the potential risks and mitigation strategies.
In the context of C programming and memory management, consider a scenario where a custom data structure, MyStruct
, contains a dynamically allocated string using strdup
. The function process_struct
receives a pointer to MyStruct
and performs several operations, including modifying the string. Which of the following sequences of actions would MOST comprehensively ensure memory safety and prevent leaks when process_struct
completes its execution, assuming no exceptions or early returns occur within the function?
In the context of C programming and memory management, consider a scenario where a custom data structure, MyStruct
, contains a dynamically allocated string using strdup
. The function process_struct
receives a pointer to MyStruct
and performs several operations, including modifying the string. Which of the following sequences of actions would MOST comprehensively ensure memory safety and prevent leaks when process_struct
completes its execution, assuming no exceptions or early returns occur within the function?
Given a scenario where a large dataset is processed, and numerous temporary strings are created using strdup
within a loop, what is the MOST effective strategy to minimize memory fragmentation and potential memory leaks, assuming the size of these temporary strings varies significantly?
Given a scenario where a large dataset is processed, and numerous temporary strings are created using strdup
within a loop, what is the MOST effective strategy to minimize memory fragmentation and potential memory leaks, assuming the size of these temporary strings varies significantly?
Consider a complex C program utilizing function pointers extensively for callback mechanisms. A scenario arises where a function pointer, intended to point to a specific function foo
, is inadvertently overwritten due to a memory corruption issue. What is the MOST effective debugging strategy to pinpoint the exact location in the code where this function pointer is being corrupted, assuming conventional debugging tools (like gdb
) are available?
Consider a complex C program utilizing function pointers extensively for callback mechanisms. A scenario arises where a function pointer, intended to point to a specific function foo
, is inadvertently overwritten due to a memory corruption issue. What is the MOST effective debugging strategy to pinpoint the exact location in the code where this function pointer is being corrupted, assuming conventional debugging tools (like gdb
) are available?
In the context of C, let's postulate that you are tasked with implementing a custom memory allocator using mmap
for a performance-critical application. Which strategy would MOST effectively minimize external fragmentation and maximize memory utilization, assuming allocation sizes vary widely and rapidly?
In the context of C, let's postulate that you are tasked with implementing a custom memory allocator using mmap
for a performance-critical application. Which strategy would MOST effectively minimize external fragmentation and maximize memory utilization, assuming allocation sizes vary widely and rapidly?
Consider a situation where a C program exhibits non-deterministic behavior, specifically, it crashes intermittently due to memory corruption that cannot be consistently reproduced. Which would be the MOST effective approach to diagnose these seemingly random crashes?
Consider a situation where a C program exhibits non-deterministic behavior, specifically, it crashes intermittently due to memory corruption that cannot be consistently reproduced. Which would be the MOST effective approach to diagnose these seemingly random crashes?
In the context of operator precedence in C, analyze the following expression, int a = 1, b = 2, c = 3, d = 4; int result = a++ * --b + c-- / ++d; What would be the eventual value of result
?
In the context of operator precedence in C, analyze the following expression, int a = 1, b = 2, c = 3, d = 4; int result = a++ * --b + c-- / ++d; What would be the eventual value of result
?
Examine the impact of storage class specifiers on variable linkage and lifetime within a multi-file C project. If a variable counter
is declared as static int counter = 0;
inside a function within file1.c
, and another variable with the same identifier is declared as int counter = 5;
at the file scope within file2.c
, which of the following statements accurately describes their linkage and visibility?
Examine the impact of storage class specifiers on variable linkage and lifetime within a multi-file C project. If a variable counter
is declared as static int counter = 0;
inside a function within file1.c
, and another variable with the same identifier is declared as int counter = 5;
at the file scope within file2.c
, which of the following statements accurately describes their linkage and visibility?
Consider a C program where a developer intends to create a thread-safe queue using pthreads. The queue is implemented as a circular buffer, and multiple threads will concurrently enqueue and dequeue elements. Which combination of synchronization primitives and coding practices would BEST ensure thread safety, minimize contention, and prevent deadlocks?
Consider a C program where a developer intends to create a thread-safe queue using pthreads. The queue is implemented as a circular buffer, and multiple threads will concurrently enqueue and dequeue elements. Which combination of synchronization primitives and coding practices would BEST ensure thread safety, minimize contention, and prevent deadlocks?
Within the context of the provided material and considering modern software engineering practices, what is the most significant limitation of strictly adhering to a file structure that mandates all source code resides in src/
and all headers in include/
, particularly in a large-scale, multi-component project utilizing advanced build systems like CMake or Bazel?
Within the context of the provided material and considering modern software engineering practices, what is the most significant limitation of strictly adhering to a file structure that mandates all source code resides in src/
and all headers in include/
, particularly in a large-scale, multi-component project utilizing advanced build systems like CMake or Bazel?
Assuming a hypothetical scenario where curl
opted to exclusively use fixed-length arrays for managing URL data, what cascade of architectural and performance consequences would most likely ensue, particularly concerning memory management and the handling of diverse URL lengths and structures encountered on the modern web?
Assuming a hypothetical scenario where curl
opted to exclusively use fixed-length arrays for managing URL data, what cascade of architectural and performance consequences would most likely ensue, particularly concerning memory management and the handling of diverse URL lengths and structures encountered on the modern web?
In the context of designing a generic, type-agnostic List Abstract Data Type (ADT) in C, and considering the trade-offs between type safety, performance, and memory management, which of the following approaches represents the most sophisticated and robust strategy for handling arbitrary data types within the list nodes, while minimizing the risks associated with memory leaks and type-related errors?
In the context of designing a generic, type-agnostic List Abstract Data Type (ADT) in C, and considering the trade-offs between type safety, performance, and memory management, which of the following approaches represents the most sophisticated and robust strategy for handling arbitrary data types within the list nodes, while minimizing the risks associated with memory leaks and type-related errors?
Given the constraints of the C programming language and the necessity for manual memory management, what strategies could be employed to mitigate the risks associated with memory leaks and dangling pointers when implementing a linked list data structure, particularly during node insertion and deletion operations, and how would these strategies impact the overall performance profile of the list?
Given the constraints of the C programming language and the necessity for manual memory management, what strategies could be employed to mitigate the risks associated with memory leaks and dangling pointers when implementing a linked list data structure, particularly during node insertion and deletion operations, and how would these strategies impact the overall performance profile of the list?
Considering the implementation of a hash table that uses linked lists to resolve collisions, and given a scenario where the hash function exhibits consistently poor distribution, resulting in a significant number of collisions and the formation of long linked lists within specific buckets, what advanced strategies could be employed to mitigate the performance degradation associated with these collisions, while considering the trade-offs between memory usage, computational complexity, and implementation effort?
Considering the implementation of a hash table that uses linked lists to resolve collisions, and given a scenario where the hash function exhibits consistently poor distribution, resulting in a significant number of collisions and the formation of long linked lists within specific buckets, what advanced strategies could be employed to mitigate the performance degradation associated with these collisions, while considering the trade-offs between memory usage, computational complexity, and implementation effort?
In the context of iterating through a linked list in C, what are the potential pitfalls associated with modifying the list structure during iteration, specifically when removing nodes, and how can these pitfalls be avoided to ensure the integrity of the iteration process and prevent program crashes or undefined behavior?
In the context of iterating through a linked list in C, what are the potential pitfalls associated with modifying the list structure during iteration, specifically when removing nodes, and how can these pitfalls be avoided to ensure the integrity of the iteration process and prevent program crashes or undefined behavior?
Considering the design of a clear
function for a linked list ADT in C, and given the critical importance of preventing memory leaks and dangling pointers, which of the following implementation strategies represents the most robust and defensible approach for deallocating the memory associated with the list nodes and their data, while adhering to best practices for resource management and exception safety?
Considering the design of a clear
function for a linked list ADT in C, and given the critical importance of preventing memory leaks and dangling pointers, which of the following implementation strategies represents the most robust and defensible approach for deallocating the memory associated with the list nodes and their data, while adhering to best practices for resource management and exception safety?
In the scenario that CIS*2750
transitions to a language with built-in garbage collection (e.g., Java or Go), assess how the design considerations for the List ADT, particularly around memory management and error handling, would fundamentally shift, and which aspects of the C-based implementation would become obsolete or require significant adaptation to leverage the capabilities of the new language environment.
In the scenario that CIS*2750
transitions to a language with built-in garbage collection (e.g., Java or Go), assess how the design considerations for the List ADT, particularly around memory management and error handling, would fundamentally shift, and which aspects of the C-based implementation would become obsolete or require significant adaptation to leverage the capabilities of the new language environment.
Flashcards
Loader Path
Loader Path
Loader searches the correct path for program execution.
Make Utility
Make Utility
A utility that executes commands from a description file.
Make Tasks
Make Tasks
Creating executables, removing files, reporting project status, packaging files, installing files, building libraries.
Make Alternatives
Make Alternatives
Signup and view all the flashcards
Make and Compiler Relationship
Make and Compiler Relationship
Signup and view all the flashcards
Make's Role in Code Building
Make's Role in Code Building
Signup and view all the flashcards
Vanilla Make Approach
Vanilla Make Approach
Signup and view all the flashcards
Make's Dependency Check
Make's Dependency Check
Signup and view all the flashcards
curl Library
curl Library
Signup and view all the flashcards
src Directory
src Directory
Signup and view all the flashcards
include Directory
include Directory
Signup and view all the flashcards
Make Macros
Make Macros
Signup and view all the flashcards
Linked Data Records
Linked Data Records
Signup and view all the flashcards
Linked List
Linked List
Signup and view all the flashcards
Insert at Front
Insert at Front
Signup and view all the flashcards
Human-readable Representation
Human-readable Representation
Signup and view all the flashcards
Default Target
Default Target
Signup and view all the flashcards
clean
Target
clean
Target
Signup and view all the flashcards
make -n
make -n
Signup and view all the flashcards
Multiline Commands
Multiline Commands
Signup and view all the flashcards
Backslash (\
)
Backslash (\
)
Signup and view all the flashcards
Makefile Macros
Makefile Macros
Signup and view all the flashcards
How Macros are Defined
How Macros are Defined
Signup and view all the flashcards
How Macros are Referenced
How Macros are Referenced
Signup and view all the flashcards
Prerequisites
Prerequisites
Signup and view all the flashcards
Recompilation Condition
Recompilation Condition
Signup and view all the flashcards
Efficiency of Makefiles
Efficiency of Makefiles
Signup and view all the flashcards
Command Line (in Makefiles)
Command Line (in Makefiles)
Signup and view all the flashcards
Command Line Indentation
Command Line Indentation
Signup and view all the flashcards
Default make
command
Default make
command
Signup and view all the flashcards
Specific Target Build
Specific Target Build
Signup and view all the flashcards
Makefile
Makefile
Signup and view all the flashcards
Pass by Address
Pass by Address
Signup and view all the flashcards
Valgrind
Valgrind
Signup and view all the flashcards
Memory Leak
Memory Leak
Signup and view all the flashcards
Compiling with -g
Compiling with -g
Signup and view all the flashcards
Valgrind Output Sections
Valgrind Output Sections
Signup and view all the flashcards
Variable Scope
Variable Scope
Signup and view all the flashcards
Storage Class
Storage Class
Signup and view all the flashcards
Access Control
Access Control
Signup and view all the flashcards
Access Levels (Java)
Access Levels (Java)
Signup and view all the flashcards
Class-Wide Scope
Class-Wide Scope
Signup and view all the flashcards
Memory Allocation and free
Memory Allocation and free
Signup and view all the flashcards
strdup() Memory Responsibility
strdup() Memory Responsibility
Signup and view all the flashcards
fopen() and fclose() Memory Responsibility
fopen() and fclose() Memory Responsibility
Signup and view all the flashcards
Study Notes
C Tool Chain & Announcements
- Student Accessibility Services needs volunteer notetakers for class notes.
- Being a volunteer contributes to academic success for fellow students.
- The volunteer notetaking position requires a one-semester commitment.
- As a volunteer, notes are shared with students approved for notetaking services due to documented disabilities.
- More details can be found at uoguel.ph/notetaker
What is a "Tool Chain"?
- Software project development is inherently tied to the tools used, including languages, libraries, and additional software.
- A "tool chain" is the sequence of software tools converting source code into binary code
- The tool chain involves a sequence of tools, making it more complex than just a compiler
Lecture Overview
- C will be used for the "native" portion (A1-A2) of the course.
- Python/SQL will be used for the UI/database portion (A3).
- The first half of the course focuses on the Big Picture of tools used by C programmers, especially on *nix systems.
- Key aspects of the lecture:
- Exposing all tools to view.
- Revealing tools "hiding" inside others.
- Understanding how they "chain" together.
- Learning how to control them.
- A goal is to elevate understanding beyond ritualized mumbo-jumbo.
The Usual Suspects
- The "five amigos" in the C toolchain are: C Preprocessor, C Compiler, Linker, Loader, and Make.
IDE (Interactive Development Environment)
- IDEs manage tools "under the hood".
- IDEs abstract the complexities of the toolchain.
- Examples:
- Windows: Visual Studio
- macOS: Xcode
- Multi-platform: Eclipse, IntelliJ, Codelite, CodeBlocks
- Different languages use different tool chains, although one IDE often supports multiple.
A Word on Compilers
- Multiple C compilers are available.
- Popular FOSS (free, open-source) compilers:
- GNU Compiler Collection (GCC): widespread, available on many platforms, often pre-installed on Linux.
- Clang: newer, an alternative to GCC, available on many platforms, installed on macOS with Xcode.
- GCC and Clang both implement C standards and offer custom extensions.
- The C compiler from GCC will primarily be used
The Big Picture: C Toolchain Components
- .c and .h files feed into the preprocessor (cpp*).
- cpp* outputs a .i file, which becomes the input for the C compiler (gcc*).
- gcc* generates an assembly file (.s), which the assembler (gas) turns into an object file (.o/.obj).
- The linker (ld*) combines object files with system libraries (.a/.lib) to produce an executable (prog.exe, a.out).
- The loader (ld.so) loads the executable into process memory at runtime for execution.
- Make automates this build-time data flow.
Creating Intermediate Files
- Intermediate files (.i, .s, .o) are not always generated by default.
- Creating .o files is sometimes required.
- Compile code with the
-save-temps
flag to see intermediate files. - The .i and .s files are almost never needed.
C Preprocessor
- Primary function: interprets # directives in .h and .c files before compilation, producing an intermediate .i file.
- Common directives:
#include
: merges header files.#define
: creates macros (with or without arguments), expanded through find-and-replace.#ifdef, #if, #else, #endif
: enables conditional compilation.
- Exception: #pragma directives are passed to the compiler and ignored if unrecognized.
- Note: Often abbreviated as "cpp", which can be confusing as "cpp" is also a file extension for C++ source files
- Note: "cpp" refers to a C preprocessor, not C++.
Prevent Multiple/Circular Includes
- Use the ".h pattern" to prevent issues.
- Inside the header file (headername.h):
#ifndef HEADERNAME_H
#define HEADERNAME_H
// body of .h file...
#endif
- This pattern defines HEADERNAME_H when the header is first included.
- If the header is included again, the file's contents are skipped.
Headers and Paths
- The
#include
directive has different syntax variants for different headers. #include <file>
: for system header files.- Searches a standard list of system directories.
#include "file"
: for header files of your own program.- Searches for
file
following these priorities:- The directory containing the current file.
- "Quote" directories.
- Standard directories (same as
<file>
).
- Searches for
Header and Path "Must Not's"
- Avoid including paths in the #include statement (e.g.
#include "../includeDir/Parser.h"
) because code will no longer compile if and/or the header file moves to a different location. - Instead, include only the file name (e.g.
#include "Parser.h"
), and allow the compiler toolchain to handle the paths.
Headers and Paths: -I Option
- Header file directories can be passed to the compiler using the
-I
option. - Example:
gcc -I../includeDir myFile.c
. - Paths specified with
-I
can be relative or absolute. - You can pass multiple include directories:
- Example:
gcc -I../includeDir -I/home/username/stuff/otherIncludeDir myFile.c
C Compiler
- Purpose: compiles C language source code (.i file) into assembly language (.s).
- Diagnoses language abuses, issues warnings and errors.
- Intermediate .i and .s files are normally deleted after assembly, unless the
-save-temps
option is used. - The sample.c,.i,.s files are found in the
GCC_intermediate_files.zip
example posted on the course website (Week 1). - Compile with
gcc -save-temps test.c.
Assembler = [G]AS
- Function: converts assembly code (.s) from the compiler into object code (.o).
- This step is normally transparent.
- There are options for controlling it, but rare to use them.
- Assembly statements can be inserted into C programs for CPU vector instruction use.
Linker (Link Editor) = ld
- Function: stitches object files (.o) into a single binary program file i.e. executable or library.
- Includes .o files of the user program and references to system libraries.
- Linkers create static and dynamic libraries.
- Static libraries (.a/.lib): inserted into the executable file.
- Dynamic libraries (.so/.dll): linked at runtime.
What is the Linker Doing?
- Object files has tables with external references e.g. calls to "printf".
- Libraries are read to define external definitions.
Libraries - Static and Dynamic
- Static and dynamic libraries are two types of libraries.
- Difference in how definitions are linked: differently with code from "printf() function • Static linking: Definitions (function code + global variables) are pulled into the program file and fixes all refs to locations. • Dynamic linking: "Makes a note" of what the library file to pull code from at runtime.
Linking and Paths - Linking Libraries
- Linker automatically links standard "C" libraries(not "C" Math libraries)
- Libraries explicitly passed with the
-l
option.- Where 'm' standard math library for linker.
Paths - Giving Linker Library Path
The linker has to know where disk location "Binaries" are
- Default: Only looks in number directory (e.g.
/usr/lib
OR/usr/local/lib
- Important: It does NOT look in current director
- Solution: use
-L
flags
*I, -L And -1
-I
used for preprocessor to find headers-L
tell linker where to find files-1
option links the library to look for a library
GCC Involvement
- GCC is a front end for {cpp, gcc, ld}.
- GCC calls those tools for you!
- GCC knows standard libraries
- Reason: makes *FLAGS portable
Loader Id.so
- Concern with create binary file from library
- "Command Shell" tells OS to execute program file
- OS opens fresh process > loads to "fill up" -> transfers in to regions into memory for process • Program instructions ("text" segment) • OS creates a new stack and an empty heap, then transfers control to first instruction of program
Loader = dlopen
- Using dynamic link library: ld.so will load program starts - but references/functions are fixed on demand
- Some use dlopen to load shared object
Loaders Note
- On Linux: check shared object use ldd
- Loader must know where shared libraries are run time
- Look for files in
Path for Loader
By default current directory is *not *included > shared libraries
Fix: Environment Variable "LD_LIBRARY_PATH."
- Export the lib:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
in.bashrc
file - Test with
ls -a
Compiling List Library
- Assignment: Simple list library and Sample code
3 files:
- LinkedListAPI.c implement library LinkedListAPI.h - Header library
StructListDemo.c - demo executable with a list
Need:
- To run Example: Must Compile Library (further lecture) Can compile Demo
- The location of Library Headers + Binary File.
Compiling Pt 2
Makefile given
- NOTE: When creating link: Linker only know which library m and "SomeLibrary"
Fix Library Errors
If it can't compile - linker. Check for library to link it
Execute list demo
- Use the loader to look into current directory
- Check for the path Then "Programs execute correctly."
Makefiles Overview
- The
make
utility executes a sequence of commands from a description file. - Typically used to create executables, but can also: remove files, report project status, package files, install files, and build libraries.
ant
in Java + Cmake butmake
is common
Makefiles: Relation to Compiler Toolchain
make
and Compiler Tollchain are separate entities.- However: make is typically used automate code building + pass flags (compilations/library names etc) flags
- Understanding compiler: essential to use makefiles.
Make - The Vanilla Approach
- Multiple ways achieve same thing
- Programmers develop styles. Expose to others.
- Learn features never seen.
- Avoid "Magical Incantation" just to use it.
- Simple convention for readability
- Never use understand what you do. Bad Idea
Makefiles - Process Overview
- Examines Dependencies between files and
date
.- Attempts build if doesnt Exist.
Makefile entries
- Made Three things:
- Target, Prerequisites , Command line
Makefile Structure: Tab Notes
Command lines MUST Prefaced w/ Tabs.
- Pain if forgotten
Makefile "part1/2/3"
- Part1: Target -> what Makefile aims build
- Part2: Prerequisites : files must exit
- Part3: Command Like: Unix Command needed (with arguments.)
Invoking Make
-
Type
make
at command -
Type
make <target>
Common Targets
- Targets dont need to Files. Can be
clean
- "All Targets," and temporary files
.o
- "All Targets," and temporary files
Checking Commands
- Check with
-n
flags
Command Lines pt 2
- Use
;
for multiple command line
Makefile Macros
Macros - AVOID typing long text. (paths,flags etc.)
- Defined with "="
- Reference using `$(LIBS), ${LIBS}
Sample Makefile pt.1 (1/3rd example with upper case)
Macro Naming Standard: Upper Case
CC = clang LIB = -Im /usr/local/lib -L. Ilmylib
prog: prog.c
This example can:
- Easily specify different compiler (instead of CLang)
- m or myLib. Include this
- Additonal library added: //user/local/lib"
Macros and More
Macros - String substitutions exist Macro CC - predefined as "Command CC" (Link to Unix "CC")
Macro LD - predefined as "Command ld"
- Can user without defined: replace with something
Macro Substituation
- Will change to O
- Reduce coding
Suffix Rules
- C file will use predefined macro command convert to Executable
Makefile Comments
- Begin with # and continue
Compiler Options + Flags
- Multiplatform Use make (cmmake)
Preprocessor Flags
-
Preprocessor: CPPFLAGS =
-
I include file_dir
This to avoid hardcoding relative or absolute paths into #include statements E.g. -I~/myproj/include Will add "~/myproj/include" to the include path, so all files in that directory can be included with a simple #include "filename.h" directive Other flags useful
-
Dsymbol value Equivalent to #define symbol value
-
DNDEBUG disable assertions
Compiler
Flags Compiler: CFLAGS = Save symbols for debugger Optimization level: 0,1,2,3
- Wall -std=c11
Linker Flags
Link Flag:
- Can use
calltest
examples
Create an output file with a specific name can be set
Code ORganziation for Library
Large c libraries often broken into libraries Headers into "include directory"
Public head -> in include, "other headers into "other directories"
The source codes into src "directory."
Binary files in more directories like \Bin, \libs
or \externs.
Notes on Code conventions
Standard for Course:
- Code in \src
- Header Files in Include
Structure of Link API
- Macro shine.
- Use macro to define location Use these macros
List API
- Abstraction to store any data/type
- "Nodes links/pointers on Data" - links others nodes + pointers
- Structure contains "Function pointers."
Common List operation
-
create a list insert a node at front/back remove a node from front/back
-
retrieve an arbitrary node iterate through a list clear/delete list create a "humanly" redable
Iterating list
- Step every data
For linked collections - use an iterator Create iterate -> traverse data collection
iterator
- Java example: iterate the elements
- c example: //Create an operator List iterate ltr =createiterate (let) Traverse list examine
- See structListDemo.cto
Libraries
- Use to develope many times!
Reusable pre-compiled functions and ancillary data types
- Example: "application programming interface." - interface user.
- Made from all public componets of your library (functions,constants, data types).
- "List API described is used libraary "StrutClustDemo.c
Public Design
- Deciding what makes up is like deciding on "public functions Class/Interface/Data struct"
- What does user want?
Private Design
- It IMPORTANT what is private That is what dont want "other programmers to see used". Hiding info - so user doesn mess stuff.
Libraries Practice
- Normally stored /ib + user.lib
- header.h contains contant One u would used Math.lib :
Static vs Dynamic
1/2 Libraries of two types static libraries are "compiles, code will copies + stores" that code in. Can compile dynamic libraries are " link together for to function. • Also known as shared libraries in the Unix/Linux world, dynamically linked libraries (DLLs) in
Static or dynamic
Dynamic library = "Flexible, non bloated" However, a lot more experience
Naming
- Libraries begin with lib
File name
libsample.so
Library Symbol
- Links used - Used multiple names to link
- Example:
libabc3.8
or3.8
dynamic library cont.
- Note: need creation of position independence
- Step create (PIC) - so it work where you want
- So it varies at run time
Done in 2 steps: "GCC + C/FP." See
Shared Library Cont.
- Need include headers w/ library
Must include
-1
(with -1)
using A library
The compile "step converted into object file" with compiler code The Link "step" links those Library Code
- Use
/lxyz
Memory and Valgrind refresher
to modify a thing in a function, we must pass its address i.e. to pointer otherwise. we modified a copy Want change value "referere"
"What Modified in function is a copy of variable"
Modifying a function
Pass it to address Value of the pointer can modify a function/address Address of the pointer is double - you access "address on address"
- We call FUNCTION. Can say "allocate + pass ADD array"
- Note in Allocate; "p" point and set address
malloc
- Allocates bits and bytes of that memory "address start block" for the system to then return that value
- This assigns "p's value to the location on thing function
- Other function, now can call that address, or can call something
- Need extra memory location
- ALL function is there"
"to modify a thing in a function, we must pass its address otherwise we're modifying a copy"
ValGrind Note
Create -> and "recommend" : Card* tmp = malloc
End - you can modify thng obj
"Address is there!"
Valgrind
- Tool check for memory leaks"
- It needs/only run on "Unix/Linux on Ubuntu shell. Or Mac's < then OS"
- Use "-n" flag to what execute and look with HEAP SUMMARY .ERROR
Tool Check Pt 2
- Also check + make "code compile and run!" - but "slow"
- Note from "Valgrind"
- "Fix + check" You are going to fix that issues
- Otherwise, never see this at all
Look into this at https://valghrind/org
ValOutput pt 2
Shows value before calling free So...
- We NEED allocate double points - not pointers for it to operate right!"
Valgrind output memory error
- Valrgind with "Memory error + Mallac" Error shows + says, "Your malloc call did NOT allocate enough memory"
- Error: the malloc is " too small + can't store it right"
Reminders
Function will use and "ONLY FREE IT," after "you finish sing it"
Scoping
-
Variables + how control
-
Note 4 types.
-
Program -> visible. • E.g. Variables declared within a method are only visible within that method (local scope)
-
Class will determine " Alive.""
-
*Access * -> who has access visible
Access
- Most are access functions/ Methods Java 4 types: public private protected.
- Class var = class scope. Visibly data struct in code Make code inaccessible."
- Example: "private"
- C has NOT ACCESS
types scope
There are 4 types of scope: • "Program" scope • "Function" scope • "File" scope • "Block" scope
Scope Cont.
- You narrowest
- Rereading
Studying That Suits You
Use AI to generate personalized quizzes and flashcards to suit your learning preferences.
Related Documents
Description
Quiz on C memory management, pointers, and Valgrind. Covers double pointers, memory allocation, using -g flag with Valgrind, and interpreting Valgrind's "still reachable" reports. Explores memory debugging and custom memory allocators.