Skip to content

Commit 8eb61fb

Browse files
committed
add c notes
1 parent 40063b4 commit 8eb61fb

File tree

2 files changed

+526
-0
lines changed

2 files changed

+526
-0
lines changed

c/c_notes.html

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,5 +666,257 @@ <h2 id="variably-modified-array-at-file-scope">Variably modified array at file s
666666
Or the compiler substitutes it everywhere beforehand?
667667
If it&#8217;s not removed by the optimization phase of the compiler, yes it is evaluated at the runtime.
668668
That means we shouldn&#8217;t take that for granted. We can assume it is evaluated at runtime.</p>
669+
670+
<h2 id="declaration-of-a-function"><code>static</code> declaration of a function</h2>
671+
672+
<p>A function declaration (prototype or even the definition) can omit the keyword <code>static</code> if it comes after another declaration of the same function with <code>static</code>.
673+
If there is one <code>static</code> declaration of a function, its first declaration has to be <code>static</code>.<br/>
674+
And a reminder: a function definition serves as a prototype; a prototype serves as a declaration.<br/>
675+
Normally you will and should have the static in the prototypes too (because they usually come first). </p>
676+
677+
<p><a href="https://stackoverflow.com/questions/15670010/does-a-static-function-need-the-static-keyword-for-the-prototype-in-c">stackoverflow: does-a-static-function-need-the-static-keyword-for-the-prototype-in-c</a></p>
678+
679+
<h2 id="supported-cc-versions-by-compiler">Supported C&#47;C++ versions by <code>gcc</code> compiler</h2>
680+
681+
<pre><code class="language-bash">gcc -v --help 2&#62;&#47;dev&#47;null | grep std=
682+
</code></pre>
683+
684+
<p>This will print all the supported C&#47;C++ versions by the compiler. Example output - </p>
685+
686+
<pre><code class="language-plaintext"> -std=c++11 Conform to the ISO 2011 C++ standard.
687+
-std=c++14 Conform to the ISO 2014 C++ standard.
688+
revised by the 2003 technical corrigendum.
689+
-std=c11 Conform to the ISO 2011 C standard.
690+
-std=c2x Conform to the ISO 202X C standard draft (experimental and incomplete support).
691+
692+
</code></pre>
693+
694+
<h2 id="how-to-pass-a-struct-member-to-without-using-a-variable">How to pass a struct member to <code>sizeof</code> without using a variable?</h2>
695+
696+
<p>Let&#8217;s say you wanted to use the size of a member of a struct as a buffer size for some other variable&#47;struct but don&#8217;t want to create an unnecessary variable of the former struct. </p>
697+
698+
<p>One way is to use a macro for the buffer size of both the struct member and the other variable. Example - </p>
699+
700+
<pre><code class="language-c">#define BUFFER_SIZE 120
701+
702+
typedef struct _mystruct
703+
{
704+
char name[BUFFER_SIZE];
705+
} mystruct;
706+
707+
char other_name[BUFFER_SIZE] = {0,};
708+
</code></pre>
709+
710+
<p>However, if you cannot change the struct definition, then you could use something like - </p>
711+
712+
<pre><code class="language-c">typedef struct _mystruct
713+
{
714+
char name[120];
715+
} mystruct;
716+
717+
char other_name[sizeof(((mystruct *)0)-&#62;name)] = {0,};
718+
</code></pre>
719+
720+
<p><code>sizeof(((mystruct *)0)-&#62;name)</code> is same as <code>sizeof(((mystruct *)NULL)-&#62;name)</code> </p>
721+
722+
<p>Dereferencing doesn&#8217;t take place inside <code>sizeof</code> operator. <code>sizeof</code> operator only sees the type of the operand. </p>
723+
724+
<p><code>sizeof</code> infers the type of <code>((mystruct *)0)-&#62;name</code>, and returns the size of that type. <code>((mystruct *)0)</code> is just a null pointer of the struct <code>mystruct</code>. <code>0-&#62;name</code> is (at compile time) an expression whose type is that of the member <code>name</code>. </p>
725+
726+
<p>The code within the <code>sizeof</code> never runs (if it did, the program would segfault!). Only the type of value within the <code>sizeof</code> is looked at. </p>
727+
728+
<p><a href="https://stackoverflow.com/questions/3553296/sizeof-single-struct-member-in-c">stackoverflow: sizeof-single-struct-member-in-c</a> </p>
729+
730+
<h2 id="warning-function-declaration-isnt-a-prototype--wstrict-prototypes">Warning: function declaration isn&#8217;t a prototype [-Wstrict-prototypes]</h2>
731+
732+
<pre><code class="language-c">int myfunc();
733+
734+
warning: function declaration isn&#39;t a prototype [-Wstrict-prototypes]
735+
11 | int myfunc();
736+
| ^~~
737+
</code></pre>
738+
739+
<p>A prototype is by definition a function declaration that specifies the type(s) of the function&#8217;s argument(s). </p>
740+
741+
<p>A non-prototype function declaration like <code>int myfunc();</code> is an old-style declaration that does not specify the number or types of arguments. </p>
742+
743+
<p>You can call such a function with any arbitrary number of arguments, and the compiler isn&#8217;t required to complain but if the call is inconsistent with the definition, your program has undefined behavior. </p>
744+
745+
<p>Logically, empty parentheses would have been a good way to specify that a function takes no arguments, but that syntax was already in use for old-style function declarations, so the ANSI C committee invented a new syntax using the void keyword <code>int myfunc(void);</code> </p>
746+
747+
<p>A function definition (which includes code for what the function actually does) also provides a declaration. </p>
748+
749+
<p>So if you have something like this - </p>
750+
751+
<pre><code class="language-c">
752+
int myfunc()
753+
{
754+
return 1;
755+
}
756+
</code></pre>
757+
758+
<p>This provides a non-prototype declaration <code>int myfunc();</code> As a definition, this tells the compiler that testlib has no parameters, but as a declaration, it only tells the compiler that testlib takes some unspecified but fixed number and type(s) of arguments. </p>
759+
760+
<p>If you change <code>()</code> to <code>(void)</code> the declaration becomes a prototype. </p>
761+
762+
<p>The advantage of a prototype is that if you accidentally call testlib with one or more arguments, the compiler will diagnose the error. </p>
763+
764+
<p><a href="https://stackoverflow.com/questions/42125/warning-error-function-declaration-isnt-a-prototype?answertab=trending#tab-top">stackoverflow: warning-error-function-declaration-isnt-a-prototype</a> </p>
765+
766+
<h2 id="nested-array-initialization">Nested array initialization</h2>
767+
768+
<pre><code class="language-c">#include &#60;stdio.h&#62;
769+
770+
typedef struct _mystruct
771+
{
772+
int s_arr[4];
773+
int number;
774+
} mystruct;
775+
776+
int main(void)
777+
{
778+
int arr[4][3] = {
779+
{1, },
780+
{2, 1, },
781+
{ [2]=4},
782+
};
783+
784+
for(int i = 0; i&#60;4; i++)
785+
{
786+
printf("arr[%d] = ", i);
787+
for(int j = 0; j&#60;3; j++)
788+
{
789+
printf("%d ", arr[i][j]);
790+
}
791+
printf("\n");
792+
}
793+
printf("\n");
794+
mystruct obj[] = {{.s_arr[2] = 3}};
795+
796+
for(int i = 0; i&#60;4; i++)
797+
{
798+
printf("obj[0].s_arr[%d] = %d\n", i, obj[0].s_arr[i]);
799+
}
800+
801+
802+
return 0;
803+
}
804+
805+
&#47;*
806+
OUTPUT -
807+
808+
arr[0] = 1 0 0
809+
arr[1] = 2 1 0
810+
arr[2] = 0 0 4
811+
arr[3] = 0 0 0
812+
813+
obj[0].s_arr[0] = 0
814+
obj[0].s_arr[1] = 0
815+
obj[0].s_arr[2] = 3
816+
obj[0].s_arr[3] = 0
817+
818+
*&#47;
819+
</code></pre>
820+
821+
<p><a href="https://en.cppreference.com/w/c/language/array_initialization">cppreference: array_initialization</a></p>
822+
823+
<h2 id="the-order-of-init-for-members-of-a-struct-doesnt-matter-in-c">The order of init for members of a struct doesn&#8217;t matter in C</h2>
824+
825+
<pre><code class="language-c">#include &#60;stdio.h&#62;
826+
827+
typedef struct _mstruct
828+
{
829+
int a[3];
830+
int b;
831+
char *c;
832+
} mstruct;
833+
834+
int main(void)
835+
{
836+
mstruct obj = {.b = 4, .a = {1, 2, }, .c = "Hi"};
837+
return 0;
838+
}
839+
</code></pre>
840+
841+
<p>This compiles without error. However, the same approach in C++ gives an error - </p>
842+
843+
<pre><code class="language-plaintext">source&#62;: In function &#39;int main()&#39;:
844+
&#60;source&#62;:12:52: error: designator order for field &#39;_mstruct::a&#39; does not match declaration order in &#39;mstruct&#39; {aka &#39;_mstruct&#39;}
845+
12 | mstruct obj = {.b = 4, .a = {1, 2, }, .c = "Hi"};
846+
|
847+
</code></pre>
848+
849+
<p><a href="https://stackoverflow.com/questions/31215971/non-trivial-designated-initializers-not-supported">stackoverflow: non-trivial-designated-initializers-not-supported</a></p>
850+
851+
<h2 id="c-version-used-by-compiler">C version used by compiler</h2>
852+
853+
<pre><code class="language-c">printf("C version = %ld\n", __STDC_VERSION__);
854+
</code></pre>
855+
856+
<p>This may output something like - <code>C version = 201710</code> </p>
857+
858+
<p>However, if you were to use a compiler flag like this - <code>--std=c11</code> , you will get output like - <code>C version = 201112</code> </p>
859+
860+
<h2 id="used-with-and-"><code>snprintf</code> used with <code>sizeof</code> and <code>strlen</code></h2>
861+
862+
<pre><code class="language-c">#include &#60;stdio.h&#62;
863+
#include &#60;string.h&#62;
864+
865+
int main(void)
866+
{
867+
char n1[4] = {&#39;0&#39;, &#39;0&#39;, &#39;0&#39;, &#39;\0&#39;};
868+
char n2[4] = {&#39;0&#39;, &#39;0&#39;, &#39;0&#39;, &#39;\0&#39;};
869+
870+
snprintf(n1, sizeof(n1), "%s", "aaa"); &#47;&#47; 4 bytes (because allocated space is 4) including &#39;\0&#39;
871+
snprintf(n2, strlen(n2), "%s", "aaa"); &#47;&#47; 3 bytes (because len is 3) including &#39;\0&#39;
872+
873+
printf("n1 = *****%s*****\n", n1);
874+
printf("n2 = *****%s*****\n", n2);
875+
return 0;
876+
}
877+
878+
&#47;*
879+
OUTPUT -
880+
881+
n1 = *****aaa*****
882+
n2 = *****aa*****
883+
884+
*&#47;
885+
</code></pre>
886+
887+
<h2 id="initialize-a-array-from-a-string">Initialize a <code>char</code> array from a string</h2>
888+
889+
<pre><code class="language-c">char arr[] = "ABCDE";
890+
</code></pre>
891+
892+
<h2 id="a-function-with-argument-accepts-a-string">A function with <code>bool</code> argument accepts a string</h2>
893+
894+
<pre><code class="language-c">#include &#60;stdio.h&#62;
895+
#include &#60;stdbool.h&#62;
896+
897+
int get_func(bool value)
898+
{
899+
if(value) return 1;
900+
return 0;
901+
}
902+
903+
int main(void)
904+
{
905+
printf("%d\n", get_func("10")); &#47;&#47; string "10" is a char ptr which is implicitly converted to bool to represent true value
906+
907+
printf("%d\n", get_func(NULL)); &#47;&#47; NULL ptr is implicitly converted to bool to represent false value
908+
return 0;
909+
}
910+
911+
&#47;*
912+
OUTPUT -
913+
914+
1
915+
0
916+
917+
*&#47;
918+
</code></pre>
919+
920+
<p><a href="https://stackoverflow.com/questions/41757634/why-a-function-with-bool-argument-accepts-string">stackoverflow: why-a-function-with-bool-argument-accepts-string</a></p>
669921
</body>
670922
</html>

0 commit comments

Comments
 (0)