Lançado · em melhoria
Guia de C · 4/6
Por enquanto, este capítulo está disponível apenas em inglês.
C has no module system or package manager built into the language. Instead, you split a program into header files (.h) holding declarations and source files (.c) holding implementations, compile each source file separately, and let the linker stitch the results together. This chapter covers that split, separate compilation, static and shared libraries, and the basics of Make and CMake.
A header contains only what other files need to know: prototypes, type definitions, and constants. Function bodies live in the source file. An include guard keeps the header harmless if it ends up included twice in the same translation unit.
// mathutil.h
#ifndef MATHUTIL_H
#define MATHUTIL_H
#include <stddef.h>
typedef struct {
double min, max, mean;
} Stats;
int clamp(int value, int lo, int hi);
Stats compute_stats(const double *values, size_t count);
#endif // MATHUTIL_H// mathutil.c
#include "mathutil.h"
static double sum(const double *values, size_t count) { // private to this file
double total = 0.0;
for (size_t i = 0; i < count; i++) total += values[i];
return total;
}
int clamp(int value, int lo, int hi) {
if (value < lo) return lo;
if (value > hi) return hi;
return value;
}
Stats compute_stats(const double *values, size_t count) {
Stats s = { values[0], values[0], 0.0 }; // assumes count >= 1
for (size_t i = 1; i < count; i++) {
if (values[i] < s.min) s.min = values[i];
if (values[i] > s.max) s.max = values[i];
}
s.mean = sum(values, count) / (double)count;
return s;
}// main.c
#include <stdio.h>
#include "mathutil.h"
int main(void) {
double data[] = {3.0, 9.5, 1.5, 6.0};
Stats s = compute_stats(data, sizeof data / sizeof data[0]);
printf("min %.1f, max %.1f, mean %.2f\n", s.min, s.max, s.mean);
printf("clamp: %d\n", clamp(120, 0, 100));
return 0;
}A few rules of thumb:
#include <...> for system headers and #include "..." for your own.static gives it internal linkage, so nothing outside the file can see it. Hide anything that is not part of the public interface.extern int counter; and define it as int counter = 0; in exactly one source file.#pragma once is not standard C, but every major compiler supports it as an alternative to include guards.Compile each source file to an object file with -c, then link the objects. When you edit one file, only that file needs recompiling.
gcc -std=c17 -Wall -Wextra -c mathutil.c -o mathutil.o
gcc -std=c17 -Wall -Wextra -c main.c -o main.o
gcc main.o mathutil.o -o stats
./statsLeave mathutil.o out of the link step and you get an error like "undefined reference to compute_stats". Compilation succeeded because the header declared the function, but the linker could not find a definition. The opposite mistake, defining the same function in two source files, produces a "multiple definition" error.
Bundling object files into a library makes them easy to reuse across programs.
| Kind | Linux | macOS | Windows | Behavior |
|---|---|---|---|---|
| Static | .a | .a | .lib | Copied into the executable at link time |
| Shared | .so | .dylib | .dll | Loaded at run time and shared between programs |
# static library
ar rcs libmathutil.a mathutil.o
gcc main.o -L. -lmathutil -o stats_static
# shared library (Linux)
gcc -fPIC -c mathutil.c -o mathutil.pic.o
gcc -shared mathutil.pic.o -o libmathutil.so
gcc main.o -L. -lmathutil -Wl,-rpath,'$ORIGIN' -o stats_shared-L adds a directory to the library search path, and -lmathutil means libmathutil.a or libmathutil.so. The GNU linker resolves symbols left to right, so list libraries after the object files that use them. A shared library also has to be found when the program runs, so either embed an rpath as above or install it to a standard library directory.
Once a project has more than a handful of files, let a build tool run the commands. Make describes rules as "target: prerequisites" followed by a recipe, and rebuilds only what is out of date. Recipe lines must be indented with a tab character, not spaces.
CC = gcc
CFLAGS = -std=c17 -Wall -Wextra -g
OBJS = main.o mathutil.o
stats: $(OBJS)
$(CC) $(OBJS) -o $@
%.o: %.c mathutil.h
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f stats $(OBJS)
.PHONY: clean$@ expands to the target and $< to the first prerequisite. Run make to build and make clean to remove the outputs.
CMake works one level higher: it generates build files for Make, Ninja, Visual Studio, and others, and it hides compiler-specific flags. That makes it the common choice for projects that build on several platforms.
cmake_minimum_required(VERSION 3.16)
project(stats C)
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
add_library(mathutil STATIC mathutil.c)
target_include_directories(mathutil PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_executable(stats main.c)
target_link_libraries(stats PRIVATE mathutil)cmake -S . -B build
cmake --build build
./build/statsChange STATIC to SHARED in add_library to produce a shared library instead. All outputs land in the separate build directory, which keeps the source tree clean.
static to keep non-public functions and globals private to their file.-c and link at the end; "undefined reference" is a link-time error.
0 comentários
Fazer login · Faça login para deixar um comentário.
Seja o primeiro a comentar.