[{"content":" The first and well-deserved #yo to @Kshitij Patil! 🚀\nIn just a few weeks since joining our mobile team, he made a strong impact - grasped knowledge around the latest Fairmatic SDK and contributed to the Android side of our React Native plugin for the latest release. ⚡\n","permalink":"https://ksh.fyi/awards/fairmatic/sit-in-driver-seat/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/fairmatic/sit-in-driver-seat/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/fairmatic/sit-in-driver-seat/featured_hu_7abee1656189af86.webp\" width=\"1200\" height=\"225\" alt=\"Slack shoutout from the Fairmatic mobile team\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003eThe first and well-deserved #yo to @Kshitij Patil! 🚀\u003c/p\u003e\n\u003cp\u003eIn just a few weeks since joining our mobile team, he made a strong impact - grasped knowledge around the latest Fairmatic SDK and contributed to the Android side of our React Native plugin for the latest release. ⚡\u003c/p\u003e\n\u003c/blockquote\u003e","title":"Sit in the driver seat"},{"content":" #GameChanger\nGreat work on the successful launch of Vibely app which is our fastest revenue growing project at the moment! The fast speed, quick app iterations and the high energy that you brought to this project was so infectious! And you did that while maintaining good design standards e.g. consistent design system. Thanks for setting standards to everyone on how to execute a fast paced project!\n","permalink":"https://ksh.fyi/awards/sharechat/game-changer/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/sharechat/game-changer/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/sharechat/game-changer/featured_hu_c47890f4a5dc252e.webp\" width=\"1200\" height=\"1262\" alt=\"ShareChat I-Achieve spot award: Game Changer\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e#GameChanger\u003c/p\u003e\n\u003cp\u003eGreat work on the successful launch of Vibely app which is our fastest revenue growing project at the moment! The fast speed, quick app iterations and the high energy that you brought to this project was so infectious! And you did that while maintaining good design standards e.g. consistent design system. Thanks for setting standards to everyone on how to execute a fast paced project!\u003c/p\u003e","title":"Game Changer: Vibely launch"},{"content":" #GameChanger\nWe are so fortunate to have Kshitij on our team! His unique understanding of design patterns and code clarity make him an invaluable asset to our organization. His humility and sound approach to problem-solving never cease to amaze us. His work in building an intervention framework improved first-time user experience. He is truly a fantastic person! We are thankful for Kshitij\u0026rsquo;s hard work and dedication and can always count on him for any task.\n","permalink":"https://ksh.fyi/awards/sharechat/interventions/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/sharechat/interventions/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/sharechat/interventions/featured_hu_64193e135a6d2f2e.webp\" width=\"1200\" height=\"1300\" alt=\"ShareChat award: Game Changer\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e#GameChanger\u003c/p\u003e\n\u003cp\u003eWe are so fortunate to have Kshitij on our team! His unique understanding of design patterns and code clarity make him an invaluable asset to our organization. His humility and sound approach to problem-solving never cease to amaze us. His work in building an intervention framework improved first-time user experience. He is truly a fantastic person! We are thankful for Kshitij\u0026rsquo;s hard work and dedication and can always count on him for any task.\u003c/p\u003e","title":"Game Changer: intervention framework"},{"content":" #ValueChampion-FirstPrinciples\nKshitij is a true champion of excellence who sets a great example for us all. His hard work, discipline, and focus on first principles are exemplary. He has been instrumental in improving processes and leads with a passion and dedication that is unmatched. We are proud to have him as a valued member of our team, and we appreciate all that he does for us. His commitment to excellence is an inspiration to us all.\n","permalink":"https://ksh.fyi/awards/sharechat/first-principles/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/sharechat/first-principles/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/sharechat/first-principles/featured_hu_bdc8aa16b7a008b3.webp\" width=\"1200\" height=\"1300\" alt=\"ShareChat award: Value Champion - First Principles\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e#ValueChampion-FirstPrinciples\u003c/p\u003e\n\u003cp\u003eKshitij is a true champion of excellence who sets a great example for us all. His hard work, discipline, and focus on first principles are exemplary. He has been instrumental in improving processes and leads with a passion and dedication that is unmatched. We are proud to have him as a valued member of our team, and we appreciate all that he does for us. His commitment to excellence is an inspiration to us all.\u003c/p\u003e","title":"Value Champion: First Principles"},{"content":" When we first started working with you to experiment with new templates for sticky notifications, you went above and beyond the problem statement. You not only implemented the new templates, but you also started work on implementing the design system and fixing bugs across the app. Your constant feedback helped us to simplify the design system semantics and make it easier for both designer and developers to use.\nWe are grateful for your contributions to ShareChat. Your ownership and commitment to quality have made a real difference. We look forward to continued collaboration with you as we make ShareChat design clean and consistent.\n","permalink":"https://ksh.fyi/awards/sharechat/design-system/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/sharechat/design-system/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/sharechat/design-system/featured_hu_7faaa572c4817f8d.webp\" width=\"1200\" height=\"1330\" alt=\"ShareChat award: Value Champion - Ownership\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003eWhen we first started working with you to experiment with new templates for sticky notifications, you went above and beyond the problem statement. You not only implemented the new templates, but you also started work on implementing the design system and fixing bugs across the app. Your constant feedback helped us to simplify the design system semantics and make it easier for both designer and developers to use.\u003c/p\u003e","title":"Value Champion: Ownership"},{"content":" #AceofInitiative\nRecognising your excellent work in setting up the entire benchmark setup for accurately measuring the app start time, and any other traces! The elaborate statistical calculations setup for every release has been very helpful!\nAlso, great job in coming up with an innovative solution for automation of testing events using network traffic - HAR files! All these efforts were instrumental in the Cheetah efforts!\nContinue innovating with unique solutions and keep up the good work! 👏👏👏\n","permalink":"https://ksh.fyi/awards/sharechat/benchmarking/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/sharechat/benchmarking/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/sharechat/benchmarking/featured_hu_41b744da5b6e294c.webp\" width=\"1200\" height=\"1394\" alt=\"ShareChat award: Ace of Initiative\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e#AceofInitiative\u003c/p\u003e\n\u003cp\u003eRecognising your excellent work in setting up the entire benchmark setup for accurately measuring the app start time, and any other traces! The elaborate statistical calculations setup for every release has been very helpful!\u003c/p\u003e\n\u003cp\u003eAlso, great job in coming up with an innovative solution for automation of testing events using network traffic - HAR files! All these efforts were instrumental in the Cheetah efforts!\u003c/p\u003e","title":"Ace of Initiative: app start benchmarking"},{"content":" #AceofInitiative\nBig shoutout for owning it and being a problem-solving wizard! Your dedication and creative thinking are major assets to our team\u0026rsquo;s success. The way you delivered Sticky Android 11 templates was outstanding!\n","permalink":"https://ksh.fyi/awards/sharechat/notifications-work/","summary":"\u003cfigure class=\"screenshot\"\u003e\n    \u003ca href=\"/awards/sharechat/notifications-work/featured.png\" title=\"Open original\"\u003e\n      \u003cimg src=\"/awards/sharechat/notifications-work/featured_hu_a2baeebf8a85f157.webp\" width=\"1200\" height=\"1178\" alt=\"ShareChat award: Ace of Initiative\" loading=\"lazy\"\u003e\n    \u003c/a\u003e\n  \u003c/figure\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e#AceofInitiative\u003c/p\u003e\n\u003cp\u003eBig shoutout for owning it and being a problem-solving wizard! Your dedication and creative thinking are major assets to our team\u0026rsquo;s success. The way you delivered Sticky Android 11 templates was outstanding!\u003c/p\u003e\n\u003c/blockquote\u003e","title":"Ace of Initiative: sticky notification templates"},{"content":"The Makefile for a one-binary C project, explained piece by piece.\nCC = gcc CFLAGS = -std=gnu23 -Og -g3 -Wall -Werror -Wextra -Wwrite-strings OUT = out BIN = $(OUT)/tinybox all: $(BIN) # Any out/\u0026lt;name\u0026gt; from \u0026lt;name\u0026gt;.c, e.g. `make out/scratch` $(OUT)/%: %.c Makefile | $(OUT) $(CC) $(CFLAGS) -o $@ $\u0026lt; $(OUT): mkdir -p $@ tinybox: $(BIN) scratch: $(OUT)/scratch run: $(BIN) ./$(BIN) clean: rm -rf $(OUT) .PHONY: all run clean tinybox scratch Rules target: prerequisites recipe make rebuilds target if it doesn\u0026rsquo;t exist or any prerequisite is newer (by file modification time). That\u0026rsquo;s the whole algorithm. The recipe lines must start with a tab. Spaces give *** missing separator. Stop. A rule with no recipe (tinybox: $(BIN)) just says \u0026ldquo;to make this, make that\u0026rdquo;. Variables CC, CFLAGS are conventional names (make\u0026rsquo;s built-in rules use them too). Use with $(NAME). Override from the command line: make CFLAGS=-O2.\nAutomatic variables Inside a recipe:\n$@: the target (out/tinybox) $\u0026lt;: the first prerequisite (tinybox.c) $^: all prerequisites The default target, and why it\u0026rsquo;s called all Plain make builds the first target in the file, whatever its name. Calling it all is a convention (GNU Coding Standards), not a requirement.\nPattern rules $(OUT)/%: %.c means \u0026ldquo;out/\u0026lt;anything\u0026gt; is built from \u0026lt;anything\u0026gt;.c\u0026rdquo;. One rule covers out/tinybox, out/scratch, and any future file. Some IDEs (e.g. CLion) only list named targets, which is why tinybox: and scratch: exist as aliases.\nThe Makefile as a prerequisite If only tinybox.c is listed, changing CFLAGS doesn\u0026rsquo;t trigger a rebuild: make says Nothing to be done and your new warning flag silently does nothing. Listing Makefile fixes that. ($\u0026lt; still picks tinybox.c, since it\u0026rsquo;s first.)\nOrder-only prerequisites: | $(OUT) Everything after | must exist before the recipe runs, but its timestamp is ignored. That matters for directories: a directory\u0026rsquo;s mtime changes whenever a file inside it is added or removed, so as a normal prerequisite it would make targets look out of date constantly.\n.PHONY Marks targets that are names, not files. Without it:\nA file called clean in the directory would make make clean think it\u0026rsquo;s up to date. make goes looking for built-in rules. It has one for foo from foo.c, so without .PHONY, make tinybox would build out/tinybox and then run gcc $(CFLAGS) tinybox.c out/tinybox -o tinybox, building a stray ./tinybox and feeding the binary in as an extra input. Phony targets skip the built-in rule search. (Fun fact: with no Makefile at all, make scratch works: the built-in rule runs cc scratch.c -o scratch.)\nHandy flags make -n: dry run, print the commands without running them make -B: rebuild everything regardless of timestamps make -p: dump the database, including all built-in rules References: info make (the GNU make manual), especially \u0026ldquo;Rule Syntax\u0026rdquo;, \u0026ldquo;Pattern Rules\u0026rdquo;, \u0026ldquo;Automatic Variables\u0026rdquo;, \u0026ldquo;Phony Targets\u0026rdquo;, \u0026ldquo;Prerequisite Types\u0026rdquo;.\n","permalink":"https://ksh.fyi/notes/makefile-basics/","summary":"\u003cp\u003eThe Makefile for a one-binary C project, explained piece by piece.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-make\" data-lang=\"make\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eCC\u003c/span\u003e     \u003cspan class=\"o\"\u003e=\u003c/span\u003e gcc\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eCFLAGS\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e -std\u003cspan class=\"o\"\u003e=\u003c/span\u003egnu23 -Og -g3 -Wall -Werror -Wextra -Wwrite-strings\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eOUT\u003c/span\u003e    \u003cspan class=\"o\"\u003e=\u003c/span\u003e out\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eBIN\u003c/span\u003e    \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003eOUT\u003cspan class=\"k\"\u003e)\u003c/span\u003e/tinybox\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eall\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003e\u003cspan class=\"nv\"\u003eBIN\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Any out/\u0026lt;name\u0026gt; from \u0026lt;name\u0026gt;.c, e.g. `make out/scratch`\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003e$(OUT)/%\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e %.\u003cspan class=\"n\"\u003ec\u003c/span\u003e \u003cspan class=\"n\"\u003eMakefile\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003e\u003cspan class=\"nv\"\u003eOUT\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003e$(\u003c/span\u003eCC\u003cspan class=\"k\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003eCFLAGS\u003cspan class=\"k\"\u003e)\u003c/span\u003e -o \u003cspan class=\"nv\"\u003e$@\u003c/span\u003e $\u0026lt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003e$(OUT)\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\tmkdir -p \u003cspan class=\"nv\"\u003e$@\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003etinybox\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003e\u003cspan class=\"nv\"\u003eBIN\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003escratch\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003e\u003cspan class=\"nv\"\u003eOUT\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e/\u003cspan class=\"n\"\u003escratch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003erun\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003e\u003cspan class=\"nv\"\u003eBIN\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t./\u003cspan class=\"k\"\u003e$(\u003c/span\u003eBIN\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eclean\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\trm -rf \u003cspan class=\"k\"\u003e$(\u003c/span\u003eOUT\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003e.PHONY\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eall\u003c/span\u003e \u003cspan class=\"n\"\u003erun\u003c/span\u003e \u003cspan class=\"n\"\u003eclean\u003c/span\u003e \u003cspan class=\"n\"\u003etinybox\u003c/span\u003e \u003cspan class=\"n\"\u003escratch\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"rules\"\u003eRules\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-make\" data-lang=\"make\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003etarget\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eprerequisites\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\trecipe\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003emake rebuilds \u003ccode\u003etarget\u003c/code\u003e if it doesn\u0026rsquo;t exist or \u003cstrong\u003eany prerequisite is newer\u003c/strong\u003e\n(by file modification time). That\u0026rsquo;s the whole algorithm.\u003c/li\u003e\n\u003cli\u003eThe recipe lines must start with a \u003cstrong\u003etab\u003c/strong\u003e. Spaces give\n\u003ccode\u003e*** missing separator.  Stop.\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eA rule with no recipe (\u003ccode\u003etinybox: $(BIN)\u003c/code\u003e) just says \u0026ldquo;to make this, make that\u0026rdquo;.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"variables\"\u003eVariables\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eCC\u003c/code\u003e, \u003ccode\u003eCFLAGS\u003c/code\u003e are conventional names (make\u0026rsquo;s built-in rules use them too).\nUse with \u003ccode\u003e$(NAME)\u003c/code\u003e. Override from the command line: \u003ccode\u003emake CFLAGS=-O2\u003c/code\u003e.\u003c/p\u003e","title":"Makefile basics for a small C project"},{"content":"Every GCC diagnostic has the same shape:\nscratch.c:3:13: error: initialization discards \u0026#39;const\u0026#39; qualifier from pointer target type [-Werror=discarded-qualifiers] 3 | char *s = \u0026#34;scratching surface\u0026#34;; | ^~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Line 1: file:line:col: severity: message [flag] scratch.c:3:13: where. Columns start at 1. Most terminals/editors make this clickable. severity: error stops the build; warning doesn\u0026rsquo;t; note: adds context to the diagnostic above it. [-Werror=discarded-qualifiers]: the flag that controls this check. -Werror= means it\u0026rsquo;s really the warning -Wdiscarded-qualifiers, promoted to an error by -Werror. Search man gcc for /Wdiscarded-qualifiers. -Wno-\u0026lt;name\u0026gt; disables it, which is rarely the right fix. The message has a fixed vocabulary The first words say where in the code the problem is:\nPhrase Means initialization the = in a declaration (T x = ...) assignment a plain x = ... passing argument N of 'f' a function call return a return statement The rest says what\u0026rsquo;s wrong. Here: \u0026ldquo;discards \u0026lsquo;const\u0026rsquo; qualifier\u0026rdquo; = a const would be lost (const/volatile are qualifiers); \u0026ldquo;from pointer target type\u0026rdquo; = the const is on the thing pointed to, not on the pointer.\nLines 2–3: the source excerpt ^ marks the column, ~~~ underlines the whole expression it\u0026rsquo;s blaming: here the literal, not s.\nnote: lines: compare the types Type errors usually come with a note giving both types:\nerror: passing argument 2 of \u0026#39;execv\u0026#39; from incompatible pointer type note: expected \u0026#39;char * const*\u0026#39; but argument is of type \u0026#39;const char * const*\u0026#39; Put them side by side and read each right to left. The difference is the bug.\nThe last line: who\u0026rsquo;s talking gcc is a driver that runs a pipeline: preprocessor → cc1 (the compiler) → as (assembler) → ld (linker, errors show up via collect2). The prefix tells you which stage complained. undefined reference to 'foo' with no line number = linker: compilation succeeded, the final link couldn\u0026rsquo;t find foo.\nHabits Fix the first error first. One missing ; or } can cause a cascade. Read the note:s. Look the flag up in man gcc before silencing it. ","permalink":"https://ksh.fyi/notes/reading-gcc-errors/","summary":"\u003cp\u003eEvery GCC diagnostic has the same shape:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003escratch.c:3:13: error: initialization discards \u0026#39;const\u0026#39; qualifier from pointer target type [-Werror=discarded-qualifiers]\n    3 |   char *s = \u0026#34;scratching surface\u0026#34;;\n      |             ^~~~~~~~~~~~~~~~~~~~\ncc1: all warnings being treated as errors\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"line-1-filelinecol-severity-message-flag\"\u003eLine 1: \u003ccode\u003efile:line:col: severity: message [flag]\u003c/code\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003escratch.c:3:13\u003c/code\u003e\u003c/strong\u003e: where. Columns start at 1. Most terminals/editors\nmake this clickable.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eseverity\u003c/strong\u003e: \u003ccode\u003eerror\u003c/code\u003e stops the build; \u003ccode\u003ewarning\u003c/code\u003e doesn\u0026rsquo;t; \u003ccode\u003enote:\u003c/code\u003e adds\ncontext to the diagnostic above it.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003e[-Werror=discarded-qualifiers]\u003c/code\u003e\u003c/strong\u003e: the flag that controls this check.\n\u003ccode\u003e-Werror=\u003c/code\u003e means it\u0026rsquo;s really the warning \u003ccode\u003e-Wdiscarded-qualifiers\u003c/code\u003e, promoted\nto an error by \u003ccode\u003e-Werror\u003c/code\u003e. Search \u003ccode\u003eman gcc\u003c/code\u003e for \u003ccode\u003e/Wdiscarded-qualifiers\u003c/code\u003e.\n\u003ccode\u003e-Wno-\u0026lt;name\u0026gt;\u003c/code\u003e disables it, which is rarely the right fix.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"the-message-has-a-fixed-vocabulary\"\u003eThe message has a fixed vocabulary\u003c/h2\u003e\n\u003cp\u003eThe first words say \u003cem\u003ewhere in the code\u003c/em\u003e the problem is:\u003c/p\u003e","title":"Reading GCC error messages"},{"content":"Read from the name outward, right to left char * const argv[] argv[] → argv is an array * const → of const pointers char → to char Rules of thumb:\n[] and () next to the name bind first (\u0026ldquo;array of\u0026rdquo;, \u0026ldquo;function returning\u0026rdquo;). Then read leftward: each * is \u0026ldquo;pointer to\u0026rdquo;. A const applies to whatever is immediately to its left; if nothing is to its left, it applies to the thing on its right. Declaration Can change the chars? Can repoint? char *p yes yes const char *p (same as char const *p) no yes char *const p yes no const char *const p no no The duplicate-const trap static const char const *v[]; // looks like \u0026#34;const pointers to const chars\u0026#34; Both consts are left of the *, so both apply to char: you\u0026rsquo;ve made the chars const twice and the pointers not at all. GCC says:\nerror: duplicate \u0026#39;const\u0026#39; declaration specifier [-Werror=duplicate-decl-specifier] What was meant: const char *const v[]. The const for the pointer goes after the *.\nWhy execv takes char *const argv[] int execv(const char *path, char *const argv[]); exec promises not to repoint the slots, but not to leave the chars alone, even though it never writes to them. The fully-const signature would have been const char *const argv[], but C won\u0026rsquo;t implicitly convert char ** to const char *const *, so every existing caller would have needed a cast. POSIX kept the old signature and documents that the strings aren\u0026rsquo;t modified (man 3p exec, RATIONALE).\nThe other direction bites if you write const-correct code:\nerror: passing argument 2 of \u0026#39;execv\u0026#39; from incompatible pointer type [-Wincompatible-pointer-types] note: expected \u0026#39;char * const*\u0026#39; but argument is of type \u0026#39;const char * const*\u0026#39; The usual answer is an explicit cast at the call, (char *const *)argv, which is safe because of the POSIX guarantee. (In GCC 14+ incompatible pointer types are an error by default, even without -Werror.)\nReferences: man 3 exec, man 3p exec; cdecl.org to check your reading.\n","permalink":"https://ksh.fyi/notes/reading-c-declarations/","summary":"\u003ch2 id=\"read-from-the-name-outward-right-to-left\"\u003eRead from the name outward, right to left\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003echar * const argv[]\n            argv[]   → argv is an array\n      * const        → of const pointers\nchar                 → to char\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eRules of thumb:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e[]\u003c/code\u003e and \u003ccode\u003e()\u003c/code\u003e next to the name bind first (\u0026ldquo;array of\u0026rdquo;, \u0026ldquo;function returning\u0026rdquo;).\u003c/li\u003e\n\u003cli\u003eThen read leftward: each \u003ccode\u003e*\u003c/code\u003e is \u0026ldquo;pointer to\u0026rdquo;.\u003c/li\u003e\n\u003cli\u003eA \u003ccode\u003econst\u003c/code\u003e applies to whatever is \u003cstrong\u003eimmediately to its left\u003c/strong\u003e; if nothing\nis to its left, it applies to the thing on its right.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eDeclaration\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eCan change the chars?\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eCan repoint?\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003echar *p\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eyes\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eyes\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003econst char *p\u003c/code\u003e (same as \u003ccode\u003echar const *p\u003c/code\u003e)\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eno\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eyes\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003echar *const p\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eyes\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eno\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003econst char *const p\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eno\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eno\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"the-duplicate-const-trap\"\u003eThe duplicate-const trap\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ev\u003c/span\u003e\u003cspan class=\"p\"\u003e[];\u003c/span\u003e   \u003cspan class=\"c1\"\u003e// looks like \u0026#34;const pointers to const chars\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eBoth \u003ccode\u003econst\u003c/code\u003es are left of the \u003ccode\u003e*\u003c/code\u003e, so both apply to \u003ccode\u003echar\u003c/code\u003e: you\u0026rsquo;ve made the\nchars const twice and the pointers not at all. GCC says:\u003c/p\u003e","title":"Reading C declarations: const, pointers, and argv"},{"content":"A string literal like \u0026quot;/bin/sh\u0026quot; is stored in .rodata, which is mapped read-only (see where things live in a C program). But its C type is plain char[N], not const char[N] (C++ fixed this, C kept it for historical reasons). So the compiler happily lets you do this:\nchar *p = \u0026#34;/bin/sh\u0026#34;; // compiles without a warning by default p[0] = \u0026#39;X\u0026#39;; // undefined behavior; in practice SIGSEGV $ ./ub Segmentation fault (exit status 139 = 128 + SIGSEGV) -Wwrite-strings: make the compiler tell you -Wwrite-strings gives literals the type const char[N], so pointing a plain char * at one becomes a warning (an error with -Werror):\nscratch.c:3:13: error: initialization discards \u0026#39;const\u0026#39; qualifier from pointer target type [-Werror=discarded-qualifiers] 3 | char *s = \u0026#34;scratching surface\u0026#34;; | ^~~~~~~~~~~~~~~~~~~~ The fix is to say what you mean: const char *s = \u0026quot;...\u0026quot;;. It\u0026rsquo;s not part of -Wall or -Wextra; you have to add it yourself.\nPointer to a literal vs. array initialized from one char *s = \u0026#34;/bin/sh\u0026#34;; // A char s[] = \u0026#34;/bin/sh\u0026#34;; // B They look almost identical but are very different:\nA is a pointer. It points at the literal itself, in .rodata. With -Wwrite-strings this is the error above. B is an array of 8 chars (7 + '\\0'). The literal is only its initializer: the bytes are copied into the array. No pointer, no const dropped, and the array is yours to modify. The variable s The bytes \u0026quot;/bin/sh\u0026quot; s[0] = 'X' A (local) 8-byte pointer on the stack the literal in .rodata UB / SIGSEGV B (local) the array itself, on the stack a copy, inside the array fine B (static or global) the array itself, in .data a copy, inside the array fine More differences:\nA can be repointed (s = \u0026quot;other\u0026quot;;). B can\u0026rsquo;t: arrays aren\u0026rsquo;t assignable, only their contents are. sizeof s is the pointer size for A and the array size for B. For \u0026quot;/bin/sh\u0026quot; both happen to be 8 on a 64-bit machine; use a longer string to see them differ. The real question isn\u0026rsquo;t \u0026ldquo;binary or stack\u0026rdquo;, it\u0026rsquo;s \u0026ldquo;am I pointing at the literal, or do I own a copy?\u0026rdquo;\nReferences: the C23 standard, sections \u0026ldquo;String literals\u0026rdquo; and \u0026ldquo;Initialization\u0026rdquo;; man gcc (-Wwrite-strings).\n","permalink":"https://ksh.fyi/notes/c-string-literals/","summary":"\u003cp\u003eA string literal like \u003ccode\u003e\u0026quot;/bin/sh\u0026quot;\u003c/code\u003e is stored in \u003ccode\u003e.rodata\u003c/code\u003e, which is mapped\nread-only (see \u003ca href=\"https://ksh.fyi/notes/c-memory-sections/\"\u003ewhere things live in a C program\u003c/a\u003e).\nBut its C type is plain \u003ccode\u003echar[N]\u003c/code\u003e, \u003cstrong\u003enot\u003c/strong\u003e \u003ccode\u003econst char[N]\u003c/code\u003e (C++ fixed this, C\nkept it for historical reasons). So the compiler happily lets you do this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/bin/sh\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e   \u003cspan class=\"c1\"\u003e// compiles without a warning by default\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;X\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e            \u003cspan class=\"c1\"\u003e// undefined behavior; in practice SIGSEGV\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ ./ub\nSegmentation fault        (exit status 139 = 128 + SIGSEGV)\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"-wwrite-strings-make-the-compiler-tell-you\"\u003e\u003ccode\u003e-Wwrite-strings\u003c/code\u003e: make the compiler tell you\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e-Wwrite-strings\u003c/code\u003e gives literals the type \u003ccode\u003econst char[N]\u003c/code\u003e, so pointing a plain\n\u003ccode\u003echar *\u003c/code\u003e at one becomes a warning (an error with \u003ccode\u003e-Werror\u003c/code\u003e):\u003c/p\u003e","title":"C string literals are read-only, but not const"},{"content":"A compiled C program is an ELF file split into sections. The loader maps them into memory with different permissions, and those permissions are what the CPU enforces at runtime.\nSection Holds Permissions Example .text machine code read + execute main .rodata read-only data read (no write) string literals, static const tables .data initialized globals / statics read + write static char buf[] = \u0026quot;hi\u0026quot;; .bss zero-initialized globals / statics read + write static int counter; stack locals, return addresses read + write char buf[8]; inside a function .data and .rodata are both in the binary; \u0026ldquo;in the binary\u0026rdquo; doesn\u0026rsquo;t mean read-only. The section decides that. .bss takes no space in the file (type NOBITS): the loader just hands out zeroed memory. Writing to .rodata (e.g. through a pointer to a string literal) → the page isn\u0026rsquo;t writable → SIGSEGV. See it yourself Sections and their flags (A = alloc, W = write, X = exec):\nreadelf -SW ./prog | grep -E \u0026#39;\\.text|\\.rodata|\\.data |\\.bss\u0026#39; [12] .text PROGBITS ... AX [14] .rodata PROGBITS ... A [22] .data PROGBITS ... WA [23] .bss NOBITS ... WA Sections are grouped into segments (readelf -lW ./prog, the LOAD lines), and segments are what actually get mapped. At runtime, compare addresses (printf(\u0026quot;%p\u0026quot;, (void *)ptr)) against /proc/self/maps:\naaaabfd80000-aaaabfd81000 r-xp ... /path/to/prog \u0026lt;- .text + .rodata (literal was here) aaaabfd9f000-aaaabfda0000 r--p ... /path/to/prog \u0026lt;- RELRO (.got etc., made read-only after startup) aaaabfda0000-aaaabfda1000 rw-p ... /path/to/prog \u0026lt;- .data / .bss (static array was here) ffffe15ba000-ffffe15db000 rw-p ... [stack] \u0026lt;- local array was here Note: on this arm64 build .rodata shares the r-xp segment with .text. Other toolchains (e.g. x86-64 with -z separate-code) give it its own r--p mapping. Either way: not writable.\nReferences: man 5 elf, man 1 readelf, man 5 proc (/proc/pid/maps).\n","permalink":"https://ksh.fyi/notes/c-memory-sections/","summary":"\u003cp\u003eA compiled C program is an ELF file split into \u003cstrong\u003esections\u003c/strong\u003e. The loader maps\nthem into memory with different permissions, and those permissions are what\nthe CPU enforces at runtime.\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eSection\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eHolds\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003ePermissions\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eExample\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e.text\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003emachine code\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eread + execute\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003emain\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e.rodata\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eread-only data\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eread (no write)\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003estring literals, \u003ccode\u003estatic const\u003c/code\u003e tables\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e.data\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003einitialized globals / statics\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eread + write\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003estatic char buf[] = \u0026quot;hi\u0026quot;;\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e.bss\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ezero-initialized globals / statics\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eread + write\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003estatic int counter;\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003estack\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003elocals, return addresses\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eread + write\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003echar buf[8];\u003c/code\u003e inside a function\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e.data\u003c/code\u003e and \u003ccode\u003e.rodata\u003c/code\u003e are both \u003cstrong\u003ein the binary\u003c/strong\u003e; \u0026ldquo;in the binary\u0026rdquo; doesn\u0026rsquo;t mean\nread-only. The section decides that.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e.bss\u003c/code\u003e takes no space in the file (type \u003ccode\u003eNOBITS\u003c/code\u003e): the loader just hands out\nzeroed memory.\u003c/li\u003e\n\u003cli\u003eWriting to \u003ccode\u003e.rodata\u003c/code\u003e (e.g. through a pointer to a string literal) → the page\nisn\u0026rsquo;t writable → \u003ccode\u003eSIGSEGV\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"see-it-yourself\"\u003eSee it yourself\u003c/h2\u003e\n\u003cp\u003eSections and their flags (\u003ccode\u003eA\u003c/code\u003e = alloc, \u003ccode\u003eW\u003c/code\u003e = write, \u003ccode\u003eX\u003c/code\u003e = exec):\u003c/p\u003e","title":"Where things live in a C program: .text, .rodata, .data, .bss, stack"}]