Assuming you are using GCC, you can get this kind of information from the GCC manual

http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options

-p

Generate extra code to write profile information suitable for the analysis program prof. You must use this option when compiling the source files you want data about, and you must also use it when linking.

-g

Produce debugging information in the operating system's native format (stabs, COFF, XCOFF, or DWARF 2). GDB can work with this debugging information.

On most systems that use stabs format, -g enables use of extra debugging information that only GDB can use; this extra information makes debugging work better in GDB but will probably make other debuggers crash or refuse to read the program. If you want to control for certain whether to generate the extra information, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below).

GCC allows you to use -g with -O. The shortcuts taken by optimized code may occasionally produce surprising results: some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some statements may not be executed because they compute constant results or their values were already at hand; some statements may execute in different places because they were moved out of loops.

Nevertheless it proves possible to debug optimized output. This makes it reasonable to use the optimizer for programs that might have bugs.

Answer from hugomg on Stack Overflow
🌐
SPEC
spec.org › cpu2017 › flags › gcc.2018-02-16.html
GNU Compiler Collection Flags
This switch may resolve duplicate symbol errors, as noted in the 502.gcc_r benchmark description. ... Enabled: Put all local arrays, even those of unknown size onto stack memory. The -fno- form disables the behavior. ... The language standards set aliasing requirements: programmers are expected to follow conventions so that the compiler can keep track of memory.
Top answer
1 of 2
8

Assuming you are using GCC, you can get this kind of information from the GCC manual

http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options

-p

Generate extra code to write profile information suitable for the analysis program prof. You must use this option when compiling the source files you want data about, and you must also use it when linking.

-g

Produce debugging information in the operating system's native format (stabs, COFF, XCOFF, or DWARF 2). GDB can work with this debugging information.

On most systems that use stabs format, -g enables use of extra debugging information that only GDB can use; this extra information makes debugging work better in GDB but will probably make other debuggers crash or refuse to read the program. If you want to control for certain whether to generate the extra information, use -gstabs+, -gstabs, -gxcoff+, -gxcoff, or -gvms (see below).

GCC allows you to use -g with -O. The shortcuts taken by optimized code may occasionally produce surprising results: some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some statements may not be executed because they compute constant results or their values were already at hand; some statements may execute in different places because they were moved out of loops.

Nevertheless it proves possible to debug optimized output. This makes it reasonable to use the optimizer for programs that might have bugs.

2 of 2
5

-p provides information for prof, and -pg provides information for gprof.

Let's look at the latter. Here's an explanation of how gprof works, but let me condense it here.

When a routine B is compiled with -pg, some code is inserted at the routine's entry point that looks up which routine is calling it, say A. Then it increments a counter saying that A called B.

Then when the code is executed, two things are happening. The first is that those counters are being incremented. The second is that timer interrupts are occurring, and there is a counter for each routine, saying how many of those interrupts happened when the PC was in the routine.

The timer interrupts happen at a certain rate, like 100 times per second. Then if, for example, 676 interrupts occurred in a routine, you can tell that its "self time" was about 6.76 seconds, spread over all the calls to it.

What the call counts allow you to do is add them up to tell how many times a routine was called, so you can divide that into its total self time to estimate how much self time per call. Then from that you can start to estimate "cumulative time". That's the time spent in a routine, plus time spent in the routines that it calls, and so on down to the bottom of the call tree.

This is all interesting technology, from 1982, but if your goal is to find ways to speed up your program, it has a lot of issues.

🌐
USC CS and ECE
bytes.usc.edu › cs104 › wiki › gcc
Usc
You’ll get some fairly strange errors about invalid reads or confusing c++ library functions. Ever thought the compiler might be able to help solve these issues before you had to slog through pages of these debugger errors? Introducing the compiler flag -O2 (that’s an O as in Oreo, or Optimize) ...
🌐
Red Hat
developers.redhat.com › blog › 2018 › 03 › 21 › compiler-and-linker-flags-gcc
Recommended compiler and linker flags for GCC | Red Hat Developer
July 2, 2024 - When you are using one of these distributions with the included compiler, this environment is recreated, requiring an extensive list of flags to be specified. Recommended flags vary between distribution versions because of toolchain and kernel limitations. The following table lists recommended build flags (as seen by the gcc and g++ compiler drivers), along with a brief description of which version of Red Hat Enterprise Linux and Fedora are applicable.
🌐
GNU
gcc.gnu.org › onlinedocs › gcc › Option-Summary.html
Option Summary (Using the GNU Compiler Collection (GCC))
-fsyntax-only -fmax-errors=n -Wpedantic -pedantic-errors -fpermissive -w -Wextra -Wall -Wabi=n -Waddress -Wno-address-of-packed-member -Waggregate-return -Walloc-size -Walloc-size-larger-than=byte-size -Walloc-zero -Walloca -Walloca-larger-than=byte-size -Wauto-profile -Wno-aggressive-loop-optimizations -Warith-conversion -Warray-bounds -Warray-bounds=n -Warray-compare -Warray-parameter -Warray-parameter=n -Wno-attributes -Wattribute-alias=n -Wno-attribute-alias -Wno-attribute-warning -Wbidi-chars=[none|unpaired|any|ucn] -Wbool-compare -Wbool-operation -Wno-builtin-declaration-mismatch -Wno-bu
🌐
Quora
quora.com › What-is-the-purpose-of-the-G-flag-when-compiling-the-C-C-program
What is the purpose of the -G flag when compiling the C/C++ program? - Quora
Answer (1 of 3): There is no standardization of compiler flags and you don’t say what compiler you are referring to. Q: What is the purpose of the -G flag when compiling the C/C++ program? Neither Clang or GCC have a [code ]-G[/code] flag. There is a [code ]-G[/code] flag for that clang MIPS ta...
Find elsewhere
🌐
Gjbex
gjbex.github.io › Defensive_programming_and_debugging › CodeValidation › Compilers › gcc_flags
Flags for gcc/g++ - Defensive programming and debugging
By default, the gcc and g++ compilers issue some warnings, but it can produce more. It is always good practice to switch on "all warnings" with -Wall. Contrary to expectations, -Wall doesn't activate all warnings though. A number of extra warnings on top of those enabled by -Wall can be switched ...
🌐
GNU
gcc.gnu.org › onlinedocs › gccint › Flags.html
Flags (GNU Compiler Collection (GCC) Internals)
This flag is required for exception handling support on targets with RTL prologues. ... During instruction scheduling, in an insn, call_insn, jump_insn or jump_table_data, indicates that the previous insn must be scheduled together with this insn. This is used to ensure that certain groups of ...
🌐
LabEx
labex.io › tutorials › linux-linux-g-command-with-practical-examples-422695
Linux g++ Command with Practical Examples | LabEx
This flag can provide significant performance improvements for programs that heavily use floating-point operations, but it may also introduce some loss of precision: g++ -O2 -ffast-math -o optimize optimize.cpp time ./optimize ... As you can see, the various compiler flags can have a significant impact on the performance of your C++ programs.
🌐
Bookmarklet Maker
caiorss.github.io › C-Cpp-Notes › compiler-flags-options.html
CPP/C++ Compiler Flags and Options
GNU Linker Command Language => GNU Linker Script Command Language, widely used for embedded systems. ... Building and Using DLLs Prev Chapter 4. Programming with Cygwin (MINGW - Windows) ... Better for debugging builds during development, since it provides faster compile-time. ... Problem: Slower compile-time and large binary size. More function inlining; loop vectorization and SIMD instructions. ... Enable (-O2), but disable some optimizations flags in order to reduce object-code size.
🌐
ScienceDirect
sciencedirect.com › topics › computer-science › compiler-flag
Compiler Flag - an overview | ScienceDirect Topics
These compilers support command-line ... popular GNU GCC compiler includes 44 optimizations enabled using the flag –O1, an additional 43 if –O2 is used, and an additional 12 if –O3 is used (see Ref....
🌐
Interrupt
interrupt.memfault.com › blog › best-and-worst-gcc-clang-compiler-flags
The Best and Worst GCC Compiler Flags For Embedded | Interrupt
October 22, 2019 - Interrupt Live: Noah Pendleton | MCU SDK Engineer @ Memfault | Thurs, January 30th - 10:30 AM ET | 7:30 AM PT | Get Notified ... Compilers have hundreds of flags and configuration settings which can be toggled to control performance optimizations, code size, error checks and diagnostic information ...
Top answer
1 of 7
74

That's kind of right, but incomplete. -g requests that the compiler and linker generate and retain source-level debugging/symbol information in the executable itself.

If...

  • the program happens to later crash and produce a core file (which suggests some problem in the actual code), or
  • a deliberate OS command forced it to core (e.g. kill -SIGQUIT pid), or
  • the program calls a function that dumps core (e.g. abort)

...- none of which are actually caused by the use of -g - then the debugger will know how to read that "-g" symbol information from the executable and cross-reference it with the core. This means you can see the proper names of variables and functions in your stack frames, get line numbers and see the source as you step around in the executable.

That debug information is useful whenever debugging - whether you started with a core or just the executable alone. It even helps produce better output from commands like pstack.

Note that your environment may have other settings to control whether cores are generated (they can be big, and there's no general way to know if/when they can be removed, so they're not always wanted). For example, on UNIX/LINUX shells it's often ulimit -c.

You may also be interested to read about DWARF Wikipedia - a commonly used debugging information format for encoding the embedded debug/symbol information in executable/library objects (e.g. on UNIX and Linux).

UPDATE per Victor's request in comments...

Symbol information lists identifiers from the source code (usually only after any name mangling needed), the (virtual) memory addresses/offsets at which they'll be loaded in the process memory, the type (e.g. data vs. code). For example...

$ cat ok.cc
int g_my_num;
namespace NS { int ns_my_num = 2; }
int f() { return g_my_num + NS::ns_my_num; }
int main() { return f(); }

$ g++ -g ok.cc -o ok    # compile ok executable with symbol info

$ nm ok    # show mangled identifiers
00000000004017c8 d _DYNAMIC
0000000000401960 d _GLOBAL_OFFSET_TABLE_
0000000000400478 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
000000000040037c T _Z1fv                     # this is f()
0000000000401798 D _ZN2NS9ns_my_numE         # this is NS::ns_my_num
00000000004017a8 d __CTOR_END__
00000000004017a0 d __CTOR_LIST__
00000000004017b8 d __DTOR_END__
00000000004017b0 d __DTOR_LIST__
0000000000400540 r __FRAME_END__
00000000004017c0 d __JCR_END__
00000000004017c0 d __JCR_LIST__
00000000004017c8 d __TMC_END__
00000000004017c8 d __TMC_LIST__
0000000000401980 A __bss_start
0000000000401788 D __data_start
0000000000400440 t __do_global_ctors_aux
00000000004002e0 t __do_global_dtors_aux
0000000000401790 d __dso_handle
0000000000000000 a __fini_array_end
0000000000000000 a __fini_array_start
                 w __gmon_start__
0000000000000000 a __init_array_end
0000000000000000 a __init_array_start
00000000004003a0 T __libc_csu_fini
00000000004003b0 T __libc_csu_init
                 U __libc_start_main
0000000000000000 a __preinit_array_end
0000000000000000 a __preinit_array_start
0000000000401980 A _edata
0000000000401994 A _end
0000000000400494 T _fini
000000000040047c T _init
0000000000400220 T _start
000000000040024c t call_gmon_start
0000000000401980 b completed.6118
0000000000401788 W data_start
0000000000400270 t deregister_tm_clones
0000000000401988 b dtor_idx.6120
0000000000401994 A end
0000000000400350 t frame_dummy
0000000000401990 B g_my_num                   # our global g_my_num
0000000000400390 T main                       # the int main() function
00000000004002a0 t register_tm_clones

$ nm ok | c++filt            # c++filt "unmangles" identifiers...
00000000004017c8 d _DYNAMIC
0000000000401960 d _GLOBAL_OFFSET_TABLE_
0000000000400478 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
000000000040037c T f()
0000000000401798 D NS::ns_my_num
00000000004017a8 d __CTOR_END__
00000000004017a0 d __CTOR_LIST__
00000000004017b8 d __DTOR_END__
00000000004017b0 d __DTOR_LIST__
0000000000400540 r __FRAME_END__
00000000004017c0 d __JCR_END__
00000000004017c0 d __JCR_LIST__
00000000004017c8 d __TMC_END__
00000000004017c8 d __TMC_LIST__
0000000000401980 A __bss_start
0000000000401788 D __data_start
0000000000400440 t __do_global_ctors_aux
00000000004002e0 t __do_global_dtors_aux
0000000000401790 d __dso_handle
0000000000000000 a __fini_array_end
0000000000000000 a __fini_array_start
                 w __gmon_start__
0000000000000000 a __init_array_end
0000000000000000 a __init_array_start
00000000004003a0 T __libc_csu_fini
00000000004003b0 T __libc_csu_init
                 U __libc_start_main
0000000000000000 a __preinit_array_end
0000000000000000 a __preinit_array_start
0000000000401980 A _edata
0000000000401994 A _end
0000000000400494 T _fini
000000000040047c T _init
0000000000400220 T _start
000000000040024c t call_gmon_start
0000000000401980 b completed.6118
0000000000401788 W data_start
0000000000400270 t deregister_tm_clones
0000000000401988 b dtor_idx.6120
0000000000401994 A end
0000000000400350 t frame_dummy
0000000000401990 B g_my_num
0000000000400390 T main
00000000004002a0 t register_tm_clones

Notes:

  • our functions f() and main() are type T (which stands for "TEXT" - used for read-only non-zero memory content whether it's actually text or other data or executable code),
  • g_my_num is B being a global with implicitly zero-ed out memory, while
  • NS::ns_my_num is D as the executable has to explicitly provide the value 2 to occupy that memory.

The man/info-page for nm documents these things further....

2 of 7
13

The -g flag tells the compiler to generate debugging information. It has no impact on whether or not a core file will be generated. On most unix-like systems, that can be setup using the ulimit command.

🌐
LabEx
labex.io › tutorials › cpp-how-to-use-compiler-flags-correctly-434220
How to use compiler flags correctly | LabEx
## Comprehensive debugging compilation g++ -g -ggdb -Wall -Wextra -pedantic -fsanitize=address,undefined ... Mastering C++ compiler flags is a fundamental skill that empowers developers to fine-tune their code's performance, implement advanced debugging strategies, and unlock the full potential of their software projects.
🌐
SPEC
spec.org › cpu2017 › flags › gcc.2021-07-21.html
GNU Compiler Collection Flags for SPEC CPU
If a call to a given function is integrated, then the function is not output as assembler code in its own right. -fno-inline-functions-called-once inhibits this optimization. ... Perform loop interchange. This flag can improve cache performance on loop nests and allow further loop optimizations to take place, such as vectorization.
🌐
Reddit
reddit.com › r/c_programming › gcc flags
r/C_Programming on Reddit: GCC flags
November 18, 2023 -

Hi,

I'm a beginner, barely scratching the surface of C at the moment. Question is, what flags do I choose for compilation? There are some "basic" like -Wall, -W, -pedantic, -ansi, -std=. GCC documentation has a ton of different flags.
Should I learn Make or CMake early to avoid retyping flags every time to compile my source files?Any help, advice are greatly appreciated.
Edit: thank you, guys. Lots of useful and interesting information. You're awesome!

Top answer
1 of 5
13
I'd recommend what you have plus Wextra. As for the second question, simply alias a build command. alias gcc_test='gcc -Wall -Wextra -pedantic -std=c99' Obviously, replace gcc_test with whatever you will remember! Then you can use gcc_test -o myprogram myprogram.c
2 of 5
4
For warnings, start with -Wall -Wextra. Everybody has a different set of flags they like on top of these. You don’t need to get everything now, just start with those two. For standard, start with -std=c11 or -std=c17. Or -std=gnu11 or -std=gnu17. The exact standard is not a big deal. Just pick one, because if you don’t pick one, you’ll get some default and you won’t know which one you’re using. Add -g so you can use the debugger. Add -fsanitize=address when you need help finding memory errors. Avoid using -pedantic. It’s not really that helpful. It just kinda gets in the way. Should I learn Make or CMake early to avoid retyping flags every time to compile my source files? My first recommendation is to use a good build system like Meson, or an IDE like Visual Studio, Code::Blocks, or Xcode. You can use CMake instead, but it kinda sucks. You can use Make, but it sucks a lot. Maybe you like these better. There are a lot of reasons why Make sucks, so I don’t recommend it to anyone. Even if you don’t use one of those build systems, you can at least write a shell script to compile everything. Paste your command line into a text file and then chmod +x that text file, so you can run it to build. For example, you could have a text file named build which looks like this: gcc -Wall -Wextra -g -std=c17 main.c lib.c Then you chmod it +x: $ chmod +x build Then you can run it: $ ./build
🌐
Red Hat
developers.redhat.com › articles › 2022 › 06 › 02 › use-compiler-flags-stack-protection-gcc-and-clang
Use compiler flags for stack protection in GCC and Clang | Red Hat Developer
August 3, 2022 - The following flags allow finer control over stack usage in applications and provide a warning when alloca() or VLA cross developer-defined thresholds: ... There are also recursion checks as well as higher-level checks on stack usage to help developers get better control of the stack behavior. Here is a full list of warnings implemented in GCC: ... Both GCC and Clang provide a wide range of compiler flags to prevent stack-based attacks.