Programming in C

Chapter 14
Professional Practice, Governance, and Emerging C Ecosystems

Bachelors Program in Electronics and Communication
Programming in C   •   Post Graduate

Professional Practice, Governance, and Emerging C Ecosystems

Introduction

C remains a strategically important language in embedded systems, telecommunications, operating systems, compilers, automotive controllers, medical devices, industrial automation, and high-performance infrastructure. Its longevity is explained not merely by execution speed, but by its combination of portability, close control over memory and hardware, mature tooling, and an extensive body of existing software.

These strengths also create professional responsibilities. A C program can access arbitrary memory, manipulate hardware registers, invoke undefined behaviour, and compromise an entire device when incorrectly designed. Consequently, advanced C practice is not limited to syntax and algorithms. It includes standards compliance, configuration management, secure development, testing, documentation, licensing, safety assurance, ethical decision-making, and the governance of technical risk.

This chapter examines C as a professional engineering ecosystem: a language, a collection of standards and tools, a body of engineering practices, and an increasingly important component of embedded, real-time, safety-critical, open-source, and heterogeneous computing systems.

Learning Objectives

After studying this chapter, the learner should be able to:

  1. Explain why governance and professional practice are essential in C development.
  2. Distinguish language standards, coding standards, safety standards, and organizational policies.
  3. Apply a disciplined C development lifecycle involving requirements, design, implementation, verification, release, and maintenance.
  4. Analyse common sources of technical and security risk in C programs.
  5. Evaluate static analysis, testing, review, and traceability as complementary assurance techniques.
  6. Explain licensing, open-source compliance, supply-chain security, and responsible disclosure.
  7. Identify emerging C ecosystems, including embedded, real-time, secure, heterogeneous, and AI-adjacent systems.
  8. Make professionally defensible engineering decisions in an applied case.

1. C as a Professional Engineering Discipline

A programming language becomes a professional discipline when software decisions affect safety, finances, privacy, public infrastructure, or organizational continuity. In such environments, “the program runs” is only one acceptance criterion. A professional system must also be understandable, reproducible, maintainable, testable, secure, and compliant with applicable requirements.

C is especially sensitive to professional discipline because its abstractions are deliberately close to machine behaviour. The programmer may control object lifetimes, storage duration, pointer arithmetic, bit fields, interrupts, volatile accesses, and binary interfaces. This control enables efficient implementation, but it increases the consequences of defects.

A useful quality model considers several dimensions:

DimensionProfessional question
Functional correctnessDoes the implementation satisfy its requirements?
ReliabilityDoes it continue to operate under expected and unusual conditions?
SafetyCan failures cause unacceptable harm?
SecurityCan an adversary violate confidentiality, integrity, or availability?
MaintainabilityCan another engineer understand and modify it safely?
PortabilityCan it be moved across compilers, processors, or operating systems?
ReproducibilityCan the same source produce an auditable, equivalent build?
ComplianceDoes it satisfy contractual, regulatory, standard, and licensing obligations?

These dimensions can conflict. For example, aggressive compiler-specific optimization may improve performance while reducing portability. A small memory footprint may be valuable in a microcontroller but may increase algorithmic complexity and maintenance cost. Professional engineering therefore requires explicit trade-offs rather than informal preference.

2. Governance: From Rules to Evidence

Governance is the system by which an organization directs, controls, and verifies technical work. It defines who may make decisions, what evidence is required, how risks are accepted, and how deviations are handled. Governance is not synonymous with bureaucracy. Good governance reduces ambiguity and makes important engineering assumptions visible.

2.1 Four layers of control

C projects commonly operate under four overlapping layers:

  1. Language standard: defines the semantics of C and the behaviour required of conforming implementations. The ISO C standard is the central reference, while compiler documentation describes implementation-specific extensions and choices.
  2. Coding standard: defines rules for naming, control flow, interfaces, comments, error handling, and prohibited constructs. MISRA C is widely used where safety, predictability, and analyzability are important.
  3. Domain or assurance standard: establishes lifecycle and evidence expectations. Examples include functional-safety, medical-device, aerospace, automotive, industrial, or cybersecurity frameworks. The applicable standard depends on the product and jurisdiction.
  4. Organizational policy: specifies approved tools, review gates, repository controls, vulnerability handling, release authority, and records retention.

A coding rule is not automatically a law, and a language guarantee is not automatically a safety guarantee. For example, a compiler may accept a construct that a coding standard prohibits because its behaviour is difficult to analyse. Conversely, a project may permit a deviation from a coding rule if the deviation is documented, reviewed, justified, and verified.

2.2 Governance artefacts

A mature project maintains evidence such as:

  • approved requirements and change history;
  • architecture and interface specifications;
  • risk assessments and hazard analyses;
  • coding-standard configuration and deviation records;
  • compiler, linker, and library versions;
  • source-control history and signed releases;
  • review records;
  • test plans, results, and coverage reports;
  • dependency and software bill of materials (SBOM) records;
  • defect, vulnerability, and corrective-action records.

The purpose of these artefacts is traceability: the ability to connect a requirement to design elements, source code, tests, results, and release decisions.

3. Standards, Portability, and Defined Behaviour

3.1 Categories of behaviour

Professional C developers distinguish among:

  • Defined behaviour: the standard specifies the result.
  • Implementation-defined behaviour: the implementation chooses among permitted alternatives and documents the choice.
  • Unspecified behaviour: the implementation may choose among permitted alternatives without documenting which choice was made.
  • Undefined behaviour: the standard imposes no requirements; the compiler may assume that the situation never occurs.
  • Constraint violation: the implementation must diagnose certain invalid programs, although a diagnostic does not guarantee that the resulting program is safe.

Undefined behaviour is particularly important because optimization can exploit assumptions that programmers do not notice. Examples include signed integer overflow, out-of-bounds access, use of an object outside its lifetime, invalid pointer arithmetic, and reading an uninitialized value in contexts where the language does not define the result.

3.2 Portability as an engineering property

Portability has several meanings. Source portability means that code can be compiled on another implementation with limited change. Behavioural portability means that the program has equivalent observable behaviour. Data portability concerns representation and interchange. Build portability concerns the ability to reproduce the build using documented tools and dependencies.

A portable interface should avoid unexamined assumptions about:

  • size and representation of integer types;
  • byte order and object layout;
  • alignment requirements;
  • character encoding;
  • width of pointers and addresses;
  • compiler extensions;
  • timing and scheduling;
  • volatile and atomic semantics;
  • operating-system and hardware services.

The standard integer types in <stdint.h> can express minimum-width requirements, such as uint32_t, when the implementation provides them. However, a fixed-width type does not by itself specify byte order, alignment, serialization format, or hardware access semantics. Those properties must be designed explicitly.

3.3 Interfaces and contracts

A professional C interface states preconditions, postconditions, ownership, lifetime, error results, and concurrency assumptions. For example, a function that accepts a buffer should specify whether the buffer may be null, whether its length is measured in bytes or elements, whether the function writes to it, and who owns its storage.

A contract may be expressed in documentation, assertions, types, naming conventions, static analysis annotations, or formal methods. An assertion is useful for detecting a violated internal invariant, but it should not replace validation of untrusted input. Assertions may also be disabled in production builds; security-critical checks must remain operational when required.

4. The Professional C Development Lifecycle

A defensible lifecycle is iterative rather than strictly linear, but it normally contains the following activities.

4.1 Requirements and risk analysis

Requirements should be testable and unambiguous. “The controller shall enter a safe state within 20 ms after detection of an over-temperature condition” is more useful than “the controller shall respond quickly.” Requirements should identify operating conditions, failure responses, timing limits, resource limits, and security assumptions.

Risk analysis asks what can go wrong, how likely it is, how severe the consequence may be, and how the risk will be controlled. In safety work, a hazard is a potentially harmful condition; a failure mode is a way in which a component may fail. In security work, threat modelling identifies adversaries, assets, attack surfaces, trust boundaries, and abuse cases.

4.2 Architecture and design

Architecture assigns responsibilities to components and defines interfaces. Important C design decisions include:

  • static versus dynamic allocation;
  • task, interrupt, and process boundaries;
  • ownership and lifetime rules;
  • error-propagation strategy;
  • hardware abstraction boundaries;
  • communication protocols;
  • synchronization and atomicity;
  • update and recovery mechanisms.

In constrained or safety-critical systems, a “no dynamic allocation after initialization” policy may reduce fragmentation and make resource use more predictable. It is not universally necessary, but it must be justified by system constraints and verified against actual requirements.

4.3 Implementation and configuration management

Source code should be maintained in a version-control system with protected branches or equivalent review controls. Builds should be reproducible from identified source revisions, compiler versions, flags, linker scripts, generated files, and dependencies. Configuration should be treated as code because a changed compiler flag or hardware definition can change behaviour as significantly as a source edit.

Warnings should be enabled at a suitably strict level, and warnings should not be indiscriminately suppressed. A warning suppression is a technical decision requiring rationale, scope, ownership, and periodic review.

4.4 Verification and validation

Verification asks whether the product was built correctly against its specification. Validation asks whether the correct product was built for its intended use. Both are required.

Important techniques include:

  • peer review and pair programming;
  • unit, integration, system, and acceptance testing;
  • boundary-value and fault-injection testing;
  • static analysis;
  • dynamic analysis and sanitizers;
  • fuzz testing of parsers and protocol handlers;
  • hardware-in-the-loop testing;
  • performance and timing measurement;
  • regression testing;
  • formal verification for selected properties.

No single technique proves that a complex C program is defect-free. Static analysis can identify suspicious paths without executing them, whereas dynamic testing observes selected executions. Test coverage measures exercised code or conditions; it does not establish the absence of untested requirements or incorrect requirements.

4.5 Release and maintenance

A release should have a unique identifier, build record, test evidence, known-issue statement, dependency inventory, and rollback or recovery plan. Maintenance includes defect correction, vulnerability response, hardware revisions, compiler upgrades, dependency changes, and end-of-life planning.

A change-impact analysis should identify affected requirements, interfaces, tests, safety arguments, threat models, and documentation. “Small code change” does not necessarily mean “small system risk.”

5. Secure and Safe C Practice

5.1 Memory and resource safety

Common vulnerabilities arise from buffer overflows, incorrect length calculations, use-after-free, double-free, null dereference, integer conversion errors, format-string misuse, and failure to check return values. A robust design establishes ownership and bounds before implementation.

For an array with n elements indexed from zero, valid indices satisfy:

0 ≤ i < n

Here, i is the index and n is the number of elements; both must be interpreted consistently, and n must not be negative. This simple condition becomes unsafe when arithmetic used to calculate n overflows or when bytes and elements are confused.

Defensive practices include validating lengths before arithmetic, using size-aware interfaces, checking allocation results, limiting parser work, clearing sensitive data where the implementation permits, and making failure states explicit. Integer overflow must be analysed in relation to the type and operation; unsigned arithmetic is modular, whereas signed overflow is not a portable wraparound mechanism.

5.2 Concurrency and interrupts

A variable shared between an interrupt handler and ordinary code requires more than the volatile qualifier. volatile tells the implementation that accesses are observable and must not be optimized away in certain ways; it does not generally provide atomicity, mutual exclusion, or a memory-ordering protocol. Atomic operations, interrupt masking, locks, or carefully designed lock-free structures may be required, depending on the platform.

Concurrency designs should document which context owns data, which operations are atomic, how circular buffers are synchronized, and what happens if a producer outpaces a consumer. Race conditions are often intermittent and therefore particularly difficult to reproduce after deployment.

5.3 Security engineering

Secure C development includes threat modelling, least privilege, input validation, cryptographic review, secure boot or update design where applicable, secret management, logging without sensitive-data leakage, and vulnerability response. Cryptographic primitives should normally come from reviewed libraries rather than ad hoc implementation.

A vulnerability disclosure process should provide a reporting channel, triage criteria, severity assessment, affected-version analysis, remediation, communication, and coordinated publication. Concealing a known defect because it is embarrassing is professionally and socially harmful.

6. Quality Assurance and Metrics

Metrics support judgement but do not replace it. Useful measures include defect density, escaped defects, review findings, build reproducibility, test pass rate, and time to remediate vulnerabilities. A metric becomes dangerous when teams optimize the number rather than the underlying quality.

Cyclomatic complexity is often used as an indicator of control-flow complexity. For a control-flow graph, a commonly used expression is:

M = E − N + 2P

where M is cyclomatic complexity, E is the number of control-flow edges, N is the number of nodes, and P is the number of connected components, usually P = 1 for a single function. Under the graph-model assumptions, M estimates the number of linearly independent paths and can inform testing effort. It is not a direct measure of correctness, readability, or security.

Coverage should be interpreted with purpose. Statement coverage shows which statements executed; branch coverage examines decision outcomes; condition coverage examines Boolean subexpressions; requirements coverage asks whether specified behaviour has corresponding tests. High code coverage with weak assertions can still provide poor assurance.

7. Licensing, Open Source, and Supply-Chain Governance

Modern C projects depend on compilers, standard libraries, RTOS kernels, middleware, cryptographic packages, build tools, and generated code. Each dependency may carry licence, vulnerability, provenance, and maintenance implications.

A project should maintain an SBOM identifying components and versions. Licence review should determine obligations such as attribution, redistribution terms, source-code availability under particular conditions, notice preservation, and compatibility with the product’s distribution model. Developers should not copy code from the internet without establishing its origin and licence.

Supply-chain controls include pinned dependency versions, verified downloads, protected build infrastructure, signed artefacts, review of build scripts, reproducible or independently verifiable builds, and monitoring of advisories. Dependency pinning improves reproducibility but can delay security fixes; therefore, update policy must balance stability and exposure.

8. Emerging C Ecosystems

8.1 Embedded and real-time systems

C remains central to microcontrollers, sensor nodes, base-station components, avionics subsystems, and industrial controllers. Emerging practice combines C with RTOS kernels, hardware description tools, model-based design, secure boot, remote update, and hardware-assisted isolation.

Real-time correctness includes timing, not merely logical output. A system may be functionally correct but unacceptable if it misses a deadline. Timing analysis must consider interrupt latency, scheduling, cache effects, bus contention, compiler optimization, and worst-case execution conditions.

8.2 Heterogeneous and high-performance systems

C increasingly interacts with GPUs, accelerators, vector units, network processors, and parallel runtimes. Interfaces may involve DMA buffers, explicit synchronization, memory-mapped devices, and foreign-function boundaries. Correctness requires attention to alignment, ownership, cache coherency, and memory ordering.

8.3 Safer systems programming

Contemporary ecosystems often combine C with languages that provide stronger memory-safety guarantees. C may remain at hardware or operating-system boundaries while safer components manage higher-level logic. Interoperability requires explicit contracts for representation, ownership, error handling, calling conventions, and unwinding behaviour.

This is not a simple replacement narrative. C has mature toolchains and direct hardware access, while safer languages may reduce classes of defects but introduce learning, tooling, certification, or ecosystem constraints. A rational architecture assigns each language the responsibilities for which it is technically and organizationally suitable.

8.4 C23 and evolving language practice

Recent revisions of the C standard continue to clarify language features and modernize selected facilities. Adoption is gradual because compiler support, embedded toolchains, certification baselines, and legacy codebases differ. Teams should specify the supported language version, compiler conformance expectations, permitted extensions, and migration strategy rather than assuming that a compiler’s default mode is portable.

8.5 AI-assisted development

AI coding assistants can generate boilerplate, explain diagnostics, propose tests, and help migrate interfaces. They can also produce plausible but incorrect code, reproduce insecure patterns, invent APIs, omit error handling, or introduce licensing uncertainty. Generated code must therefore be treated as an untrusted proposal.

A professional workflow requires human review, compilation with strict diagnostics, static and dynamic analysis, tests derived from requirements, provenance checks, and protection of confidential source or credentials. AI must not be used to bypass review gates or to fabricate evidence of testing. In safety- or security-critical systems, organizational policy should define where AI assistance is permitted and what records must be retained.

9. Illustrative Case Study: Firmware for an Industrial Temperature Controller

This is a fictional illustrative case.

Background

A manufacturer develops a C-based controller for an industrial heater. The controller samples temperature, drives a power relay, records faults, and accepts configuration through a serial protocol. A thermal excursion could damage equipment or injure personnel.

Problem

A prototype appears reliable in normal tests but occasionally resets during communication bursts. A review also finds that the serial parser copies a declared message length into a fixed buffer without adequately validating the length. The project schedule is tight, and a manager proposes disabling several compiler warnings to obtain a clean build.

Analysis

The reset is potentially related to stack exhaustion, buffer corruption, watchdog behaviour, or a race between the receive interrupt and parser. The unchecked length is a directly exploitable memory-safety defect. Disabling warnings would remove evidence rather than remove the cause. The safety requirement is not simply “control temperature”; it includes detection of sensor faults, relay failure, invalid configuration, processor failure, and communication abuse.

Approach and solution

The team first freezes the prototype for forensic analysis and creates a traceability matrix linking hazards to requirements, design controls, and tests. It then:

  1. defines a bounded frame format with explicit maximum length and checksum;
  2. validates lengths before allocation, copying, and arithmetic;
  3. separates interrupt-level reception from parser processing using a reviewed ring buffer;
  4. makes ownership and concurrency assumptions explicit;
  5. adds watchdog diagnostics and a safe output state;
  6. uses static analysis, compiler warnings, sanitizers in host tests, fuzzing, and hardware-in-the-loop tests;
  7. records justified deviations from the selected coding standard;
  8. requires two-person review for safety-related changes;
  9. creates a signed release image and rollback procedure;
  10. tests sensor disconnection, stuck relays, corrupted frames, burst traffic, power interruption, and timing extremes.

Outcome

The team identifies both the parser overflow and a race in ring-buffer index handling. After correction, stress tests run beyond the required operating interval without unexplained resets. More importantly, the organization gains evidence that the controller enters a defined safe state for invalid input and sensor failure. The release decision is based on requirements and evidence rather than on the absence of visible failures.

Learning points

The case demonstrates that security and safety are connected but not identical; coding standards are controls, not substitutes for analysis; warnings are evidence; concurrency must be designed explicitly; and governance improves engineering decisions when schedules are pressured.

10. Professional Responsibilities and Ethical Judgement

Engineers have obligations to users, employers, colleagues, and society. They should communicate material risks honestly, protect confidential information, respect licences, avoid misleading claims, preserve technical records, and escalate conditions that may cause serious harm. A developer should not certify tests that were not performed or represent a prototype as production-ready without qualification.

Ethical judgement is often required when commercial pressure conflicts with assurance. A proportionate response is to document the risk, identify alternatives, estimate consequences, involve the responsible technical and safety authorities, and use established escalation channels. Professionalism does not mean refusing every risk; it means making risk visible and accepting it through authorized, informed decisions.

Best-Practice Checklist

  • Define the supported C standard, compiler, target, and extensions.
  • Establish ownership, lifetime, bounds, and error contracts for interfaces.
  • Treat warnings, static-analysis findings, and test failures as managed evidence.
  • Use review and automated checks together.
  • Separate safety arguments from security threat models, while analysing their interactions.
  • Maintain traceability from requirements to tests and release evidence.
  • Inventory dependencies, licences, vulnerabilities, and build inputs.
  • Protect the build and release pipeline.
  • Document deviations and revisit them after toolchain or requirement changes.
  • Treat AI-generated code as untrusted until independently verified.
  • Plan maintenance, vulnerability disclosure, updates, rollback, and end of life.

Chapter Summary

Professional C development extends beyond writing syntactically valid programs. It requires governance, standards awareness, explicit contracts, disciplined lifecycle management, reproducible builds, and evidence-based verification. Defined, implementation-defined, unspecified, and undefined behaviour must be distinguished because portability and optimization depend on these categories. Secure practice addresses memory safety, integer operations, concurrency, input validation, cryptography, and vulnerability response. Quality assurance combines reviews, static analysis, testing, fuzzing, sanitizers, coverage, and—where appropriate—formal reasoning; no single method is sufficient.

Open-source licensing and software supply-chain governance are now central responsibilities because C systems depend on extensive external infrastructure. Emerging ecosystems place C alongside RTOS platforms, heterogeneous processors, secure boot, hardware isolation, safer languages, and AI-assisted tools. The professional engineer uses these technologies critically, preserves human accountability, and makes risk, assumptions, and evidence visible throughout the system lifecycle.

Key Terms

Language standard: A specification defining the syntax and semantics of C.

Coding standard: Rules intended to improve consistency, analyzability, safety, or maintainability.

Undefined behaviour: A situation for which the C standard imposes no requirements.

Implementation-defined behaviour: Behaviour selected and documented by an implementation.

Traceability: The ability to relate requirements, design, code, tests, and evidence.

Static analysis: Examination of software without executing the analysed program.

Dynamic analysis: Examination based on program execution.

Cyclomatic complexity: A control-flow measure used to estimate independent paths.

Assertion: A programmed check of an assumed condition or invariant.

Threat model: A structured description of assets, adversaries, attack surfaces, and threats.

Hazard: A condition with potential to cause harm.

SBOM: A software bill of materials listing components and versions in a product.

Reproducible build: A build that can be recreated with equivalent inputs and results.

Vulnerability disclosure: The process of reporting, analysing, correcting, and communicating security defects.

Ownership: The defined responsibility for a resource’s use, lifetime, and release.

Memory ordering: Rules governing the visibility and ordering of concurrent memory operations.

Technical debt: Future cost created by expedient or inadequately controlled technical decisions.

Deviation record: Documented justification and approval for departing from a required rule.

Functional safety: The part of overall safety dependent on correct operation of systems and controls.

AI-assisted development: Use of artificial-intelligence tools to support software engineering activities.

Review Questions

Short Answer Questions

  1. Distinguish defined, implementation-defined, unspecified, and undefined behaviour in C.
  2. Why is volatile insufficient as a general solution to concurrency problems?
  3. What purposes does an SBOM serve?
  4. Explain the difference between verification and validation.
  5. Why should AI-generated C code be treated as an untrusted proposal?

Long Answer Questions

  1. Discuss how language standards, coding standards, domain standards, and organizational policies interact in a professional C project.
  2. Explain a complete lifecycle for developing and maintaining safety- or security-relevant C software.
  3. Analyse the relationship among static analysis, testing, code review, fuzzing, and formal methods.
  4. Discuss the major portability risks associated with data representation, compiler extensions, concurrency, and hardware interfaces.
  5. Evaluate the advantages and limitations of combining C with memory-safe languages in embedded and systems software.

Analytical / Application Questions

  1. A parser receives a 16-bit length field and copies that many bytes into a 256-byte array. Identify the risks, define the required validation conditions, and propose a verification strategy.
  2. A project has excellent statement coverage but frequent field failures. Analyse why coverage has not guaranteed reliability and recommend additional evidence.
  3. An organization wants to use an AI assistant with proprietary C firmware. Design a governance policy addressing confidentiality, provenance, review, testing, licensing, and accountability.

Multiple Choice Questions with Answers

Question 1

Which category of C behaviour imposes no requirements on the implementation?

A. Defined behaviour

B. Implementation-defined behaviour

C. Unspecified behaviour

D. Undefined behaviour

Correct Answer: D. Undefined behaviour

Question 2

What is the primary purpose of a software bill of materials?

A. To list software components and versions used in a product

B. To replace all software testing

C. To measure processor clock frequency

D. To define C pointer arithmetic

Correct Answer: A. To list software components and versions used in a product

Question 3

Why does volatile generally not solve a shared-data concurrency problem?

A. It prevents compilation of interrupt handlers

B. It does not by itself provide atomicity or mutual exclusion

C. It automatically allocates dynamic memory

D. It changes signed integers into unsigned integers

Correct Answer: B. It does not by itself provide atomicity or mutual exclusion

Question 4

For a single connected control-flow graph, which expression is commonly used for cyclomatic complexity?

A. M = E + N + 2P

B. M = E − N + 2P

C. M = N − E + P

D. M = E × N × P

Correct Answer: B. M = E − N + 2P

Question 5

Which practice most directly improves reproducibility of a C build?

A. Removing version information from dependencies

B. Changing compiler flags for each developer

C. Recording source, toolchain, flags, and dependency versions

D. Suppressing all compiler warnings

Correct Answer: C. Recording source, toolchain, flags, and dependency versions

Question 6

What does verification primarily ask?

A. Whether the correct product was selected for the market

B. Whether the product was built according to its specification

C. Whether every user prefers the interface

D. Whether the source code has no comments

Correct Answer: B. Whether the product was built according to its specification

Question 7

Which statement about a coding-standard deviation is most professionally appropriate?

A. It should be hidden to avoid audit findings

B. It should be documented, justified, reviewed, and verified

C. It automatically makes the code non-compilable

D. It eliminates the need for testing

Correct Answer: B. It should be documented, justified, reviewed, and verified

Question 8

For an array containing n elements, which condition describes a valid zero-based index i?

A. i ≤ 0 or i > n

B. 0 < i ≤ n

C. 0 ≤ i < n

D. i ≥ n

Correct Answer: C. 0 ≤ i < n

Question 9

Which activity is most directly associated with identifying adversaries, assets, and attack surfaces?

A. Threat modelling

B. Link-time optimization

C. Code formatting

D. Binary sorting

Correct Answer: A. Threat modelling

Question 10

What is the most appropriate treatment of code generated by an AI assistant?

A. Accept it without review because it is machine-generated

B. Treat it as an untrusted proposal requiring independent verification

C. Use it only after deleting all tests

D. Assume its licensing is automatically unrestricted

Correct Answer: B. Treat it as an untrusted proposal requiring independent verification

Programming in C
Chapter 14 of 14