Function call with more parameters than expected





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







6















I was reviewing some code and I came across something similar to this.



File foo.c:



int bar(int param1)
{
return param1*param1;
}


File main.c:



#include <stdio.h>

int bar(int param1, int unusedParam);

int main (void)
{
int param = 2, unused = 0;
printf("%dn", bar(param, unused));
}


Running gcc main.c foo.c -Wall --pedantic -O0 it compiles, links and works properly without throwing a single warning in the process. Why is that?



Thanks!










share|improve this question

























  • Because you didn't include a header file foo.hcontaining the function prototype int bar(int param1);.

    – Jabberwocky
    Nov 22 '18 at 15:28











  • This may have to do with linking to DLLs or shared libraries

    – stackptr
    Nov 22 '18 at 15:28











  • I get that it may work properly, but I don't know why the linker does not find this inconsistency and warn you about it.

    – Kai
    Nov 22 '18 at 15:28











  • Put the content of foo.c before main in main.c and compile that, you'll get a at least a warning, but more likely an error.

    – Jabberwocky
    Nov 22 '18 at 15:30






  • 2





    I think I'm starting to get it. Both files can compile independently so main.c thinks that the function has two parameters and pushes them onto the stack. The linker does not really care about parameters just solving symbols. Am I right?

    – Kai
    Nov 22 '18 at 15:56


















6















I was reviewing some code and I came across something similar to this.



File foo.c:



int bar(int param1)
{
return param1*param1;
}


File main.c:



#include <stdio.h>

int bar(int param1, int unusedParam);

int main (void)
{
int param = 2, unused = 0;
printf("%dn", bar(param, unused));
}


Running gcc main.c foo.c -Wall --pedantic -O0 it compiles, links and works properly without throwing a single warning in the process. Why is that?



Thanks!










share|improve this question

























  • Because you didn't include a header file foo.hcontaining the function prototype int bar(int param1);.

    – Jabberwocky
    Nov 22 '18 at 15:28











  • This may have to do with linking to DLLs or shared libraries

    – stackptr
    Nov 22 '18 at 15:28











  • I get that it may work properly, but I don't know why the linker does not find this inconsistency and warn you about it.

    – Kai
    Nov 22 '18 at 15:28











  • Put the content of foo.c before main in main.c and compile that, you'll get a at least a warning, but more likely an error.

    – Jabberwocky
    Nov 22 '18 at 15:30






  • 2





    I think I'm starting to get it. Both files can compile independently so main.c thinks that the function has two parameters and pushes them onto the stack. The linker does not really care about parameters just solving symbols. Am I right?

    – Kai
    Nov 22 '18 at 15:56














6












6








6


1






I was reviewing some code and I came across something similar to this.



File foo.c:



int bar(int param1)
{
return param1*param1;
}


File main.c:



#include <stdio.h>

int bar(int param1, int unusedParam);

int main (void)
{
int param = 2, unused = 0;
printf("%dn", bar(param, unused));
}


Running gcc main.c foo.c -Wall --pedantic -O0 it compiles, links and works properly without throwing a single warning in the process. Why is that?



Thanks!










share|improve this question
















I was reviewing some code and I came across something similar to this.



File foo.c:



int bar(int param1)
{
return param1*param1;
}


File main.c:



#include <stdio.h>

int bar(int param1, int unusedParam);

int main (void)
{
int param = 2, unused = 0;
printf("%dn", bar(param, unused));
}


Running gcc main.c foo.c -Wall --pedantic -O0 it compiles, links and works properly without throwing a single warning in the process. Why is that?



Thanks!







c parameter-passing calling-convention






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 15 at 19:47









Govind Parmar

13.1k53764




13.1k53764










asked Nov 22 '18 at 15:25









KaiKai

503




503













  • Because you didn't include a header file foo.hcontaining the function prototype int bar(int param1);.

    – Jabberwocky
    Nov 22 '18 at 15:28











  • This may have to do with linking to DLLs or shared libraries

    – stackptr
    Nov 22 '18 at 15:28











  • I get that it may work properly, but I don't know why the linker does not find this inconsistency and warn you about it.

    – Kai
    Nov 22 '18 at 15:28











  • Put the content of foo.c before main in main.c and compile that, you'll get a at least a warning, but more likely an error.

    – Jabberwocky
    Nov 22 '18 at 15:30






  • 2





    I think I'm starting to get it. Both files can compile independently so main.c thinks that the function has two parameters and pushes them onto the stack. The linker does not really care about parameters just solving symbols. Am I right?

    – Kai
    Nov 22 '18 at 15:56



















  • Because you didn't include a header file foo.hcontaining the function prototype int bar(int param1);.

    – Jabberwocky
    Nov 22 '18 at 15:28











  • This may have to do with linking to DLLs or shared libraries

    – stackptr
    Nov 22 '18 at 15:28











  • I get that it may work properly, but I don't know why the linker does not find this inconsistency and warn you about it.

    – Kai
    Nov 22 '18 at 15:28











  • Put the content of foo.c before main in main.c and compile that, you'll get a at least a warning, but more likely an error.

    – Jabberwocky
    Nov 22 '18 at 15:30






  • 2





    I think I'm starting to get it. Both files can compile independently so main.c thinks that the function has two parameters and pushes them onto the stack. The linker does not really care about parameters just solving symbols. Am I right?

    – Kai
    Nov 22 '18 at 15:56

















Because you didn't include a header file foo.hcontaining the function prototype int bar(int param1);.

– Jabberwocky
Nov 22 '18 at 15:28





Because you didn't include a header file foo.hcontaining the function prototype int bar(int param1);.

– Jabberwocky
Nov 22 '18 at 15:28













This may have to do with linking to DLLs or shared libraries

– stackptr
Nov 22 '18 at 15:28





This may have to do with linking to DLLs or shared libraries

– stackptr
Nov 22 '18 at 15:28













I get that it may work properly, but I don't know why the linker does not find this inconsistency and warn you about it.

– Kai
Nov 22 '18 at 15:28





I get that it may work properly, but I don't know why the linker does not find this inconsistency and warn you about it.

– Kai
Nov 22 '18 at 15:28













Put the content of foo.c before main in main.c and compile that, you'll get a at least a warning, but more likely an error.

– Jabberwocky
Nov 22 '18 at 15:30





Put the content of foo.c before main in main.c and compile that, you'll get a at least a warning, but more likely an error.

– Jabberwocky
Nov 22 '18 at 15:30




2




2





I think I'm starting to get it. Both files can compile independently so main.c thinks that the function has two parameters and pushes them onto the stack. The linker does not really care about parameters just solving symbols. Am I right?

– Kai
Nov 22 '18 at 15:56





I think I'm starting to get it. Both files can compile independently so main.c thinks that the function has two parameters and pushes them onto the stack. The linker does not really care about parameters just solving symbols. Am I right?

– Kai
Nov 22 '18 at 15:56












2 Answers
2






active

oldest

votes


















9














This really depends on the calling convention and architecture. For example, with cdecl on x86, where arguments are pushed right to left and the caller restores the stack, the presence of an additional parameter is transparent to the function bar:



push    11
push 10
call _bar
add esp, 8


bar will only "see" the 10, and will function as expected with that parameter, returning 100. The stack is restored afterwards so there is no misalignment in main either; if you had just passed the 10 it would have added 4 to esp instead.



This is also true of the x64 calling conventions for both MSVC on Windows and the System V ABI, where the first few1 integral arguments are passed in registers; the second argument will be populated in its designated register by the call in main, but not even looked at by bar.



If, however, you tried to use an alternate calling convention where the callee is responsible for cleaning up the stack, you would run into trouble either at the build stage or (worse) at runtime. stdcall, for example, decorates the function name with the number of bytes used by the argument list, so I'm not even able to link the final executable by changing bar to use stdcall instead:



error LNK2019: unresolved external symbol _bar@8 referenced in function _main


This is because bar now has the signature _bar@4 in its object file, as it should.



This gets interesting if you use the obsolete calling convention pascal, where parameters are pushed left-to-right:



push 10
push 11
call _bar


Now bar returns 121, not 100, like you expected. That is, if the function successfully returns, which it won't, since the callee was supposed to clean up the stack but failed due to the extra parameter, trashing the return address.



1: 4 for MSVC on Windows; 6 on System V ABI






share|improve this answer


























  • I have ... ah, thanks, Angew.

    – Peter A. Schneider
    Nov 22 '18 at 15:39











  • Only four arguments are passed in registers in msvc.

    – Biswapriyo
    Nov 23 '18 at 3:07











  • @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

    – Govind Parmar
    Nov 23 '18 at 22:05











  • @GovindParmar you are saying that on x86 in this case second variable is signored.

    – Gox
    Feb 15 at 19:40











  • @Gox If the calling convention is cdecl, then yes.

    – Govind Parmar
    Feb 15 at 19:42



















2














Normally you'd have this file structure:



foo.c



#include "foo.h"

int bar(int param1)
{
return param1*param1;
}


foo.h



int bar(int param1);


main.c



#include <stdio.h>
#include "foo.h"

int main (void)
{
int param = 2, unused = 0;
printf("%dn", bar(param, unused));
}


Now you'll get a compilation error as soon as you use bar with non matching parameters.






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53434075%2ffunction-call-with-more-parameters-than-expected%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    9














    This really depends on the calling convention and architecture. For example, with cdecl on x86, where arguments are pushed right to left and the caller restores the stack, the presence of an additional parameter is transparent to the function bar:



    push    11
    push 10
    call _bar
    add esp, 8


    bar will only "see" the 10, and will function as expected with that parameter, returning 100. The stack is restored afterwards so there is no misalignment in main either; if you had just passed the 10 it would have added 4 to esp instead.



    This is also true of the x64 calling conventions for both MSVC on Windows and the System V ABI, where the first few1 integral arguments are passed in registers; the second argument will be populated in its designated register by the call in main, but not even looked at by bar.



    If, however, you tried to use an alternate calling convention where the callee is responsible for cleaning up the stack, you would run into trouble either at the build stage or (worse) at runtime. stdcall, for example, decorates the function name with the number of bytes used by the argument list, so I'm not even able to link the final executable by changing bar to use stdcall instead:



    error LNK2019: unresolved external symbol _bar@8 referenced in function _main


    This is because bar now has the signature _bar@4 in its object file, as it should.



    This gets interesting if you use the obsolete calling convention pascal, where parameters are pushed left-to-right:



    push 10
    push 11
    call _bar


    Now bar returns 121, not 100, like you expected. That is, if the function successfully returns, which it won't, since the callee was supposed to clean up the stack but failed due to the extra parameter, trashing the return address.



    1: 4 for MSVC on Windows; 6 on System V ABI






    share|improve this answer


























    • I have ... ah, thanks, Angew.

      – Peter A. Schneider
      Nov 22 '18 at 15:39











    • Only four arguments are passed in registers in msvc.

      – Biswapriyo
      Nov 23 '18 at 3:07











    • @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

      – Govind Parmar
      Nov 23 '18 at 22:05











    • @GovindParmar you are saying that on x86 in this case second variable is signored.

      – Gox
      Feb 15 at 19:40











    • @Gox If the calling convention is cdecl, then yes.

      – Govind Parmar
      Feb 15 at 19:42
















    9














    This really depends on the calling convention and architecture. For example, with cdecl on x86, where arguments are pushed right to left and the caller restores the stack, the presence of an additional parameter is transparent to the function bar:



    push    11
    push 10
    call _bar
    add esp, 8


    bar will only "see" the 10, and will function as expected with that parameter, returning 100. The stack is restored afterwards so there is no misalignment in main either; if you had just passed the 10 it would have added 4 to esp instead.



    This is also true of the x64 calling conventions for both MSVC on Windows and the System V ABI, where the first few1 integral arguments are passed in registers; the second argument will be populated in its designated register by the call in main, but not even looked at by bar.



    If, however, you tried to use an alternate calling convention where the callee is responsible for cleaning up the stack, you would run into trouble either at the build stage or (worse) at runtime. stdcall, for example, decorates the function name with the number of bytes used by the argument list, so I'm not even able to link the final executable by changing bar to use stdcall instead:



    error LNK2019: unresolved external symbol _bar@8 referenced in function _main


    This is because bar now has the signature _bar@4 in its object file, as it should.



    This gets interesting if you use the obsolete calling convention pascal, where parameters are pushed left-to-right:



    push 10
    push 11
    call _bar


    Now bar returns 121, not 100, like you expected. That is, if the function successfully returns, which it won't, since the callee was supposed to clean up the stack but failed due to the extra parameter, trashing the return address.



    1: 4 for MSVC on Windows; 6 on System V ABI






    share|improve this answer


























    • I have ... ah, thanks, Angew.

      – Peter A. Schneider
      Nov 22 '18 at 15:39











    • Only four arguments are passed in registers in msvc.

      – Biswapriyo
      Nov 23 '18 at 3:07











    • @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

      – Govind Parmar
      Nov 23 '18 at 22:05











    • @GovindParmar you are saying that on x86 in this case second variable is signored.

      – Gox
      Feb 15 at 19:40











    • @Gox If the calling convention is cdecl, then yes.

      – Govind Parmar
      Feb 15 at 19:42














    9












    9








    9







    This really depends on the calling convention and architecture. For example, with cdecl on x86, where arguments are pushed right to left and the caller restores the stack, the presence of an additional parameter is transparent to the function bar:



    push    11
    push 10
    call _bar
    add esp, 8


    bar will only "see" the 10, and will function as expected with that parameter, returning 100. The stack is restored afterwards so there is no misalignment in main either; if you had just passed the 10 it would have added 4 to esp instead.



    This is also true of the x64 calling conventions for both MSVC on Windows and the System V ABI, where the first few1 integral arguments are passed in registers; the second argument will be populated in its designated register by the call in main, but not even looked at by bar.



    If, however, you tried to use an alternate calling convention where the callee is responsible for cleaning up the stack, you would run into trouble either at the build stage or (worse) at runtime. stdcall, for example, decorates the function name with the number of bytes used by the argument list, so I'm not even able to link the final executable by changing bar to use stdcall instead:



    error LNK2019: unresolved external symbol _bar@8 referenced in function _main


    This is because bar now has the signature _bar@4 in its object file, as it should.



    This gets interesting if you use the obsolete calling convention pascal, where parameters are pushed left-to-right:



    push 10
    push 11
    call _bar


    Now bar returns 121, not 100, like you expected. That is, if the function successfully returns, which it won't, since the callee was supposed to clean up the stack but failed due to the extra parameter, trashing the return address.



    1: 4 for MSVC on Windows; 6 on System V ABI






    share|improve this answer















    This really depends on the calling convention and architecture. For example, with cdecl on x86, where arguments are pushed right to left and the caller restores the stack, the presence of an additional parameter is transparent to the function bar:



    push    11
    push 10
    call _bar
    add esp, 8


    bar will only "see" the 10, and will function as expected with that parameter, returning 100. The stack is restored afterwards so there is no misalignment in main either; if you had just passed the 10 it would have added 4 to esp instead.



    This is also true of the x64 calling conventions for both MSVC on Windows and the System V ABI, where the first few1 integral arguments are passed in registers; the second argument will be populated in its designated register by the call in main, but not even looked at by bar.



    If, however, you tried to use an alternate calling convention where the callee is responsible for cleaning up the stack, you would run into trouble either at the build stage or (worse) at runtime. stdcall, for example, decorates the function name with the number of bytes used by the argument list, so I'm not even able to link the final executable by changing bar to use stdcall instead:



    error LNK2019: unresolved external symbol _bar@8 referenced in function _main


    This is because bar now has the signature _bar@4 in its object file, as it should.



    This gets interesting if you use the obsolete calling convention pascal, where parameters are pushed left-to-right:



    push 10
    push 11
    call _bar


    Now bar returns 121, not 100, like you expected. That is, if the function successfully returns, which it won't, since the callee was supposed to clean up the stack but failed due to the extra parameter, trashing the return address.



    1: 4 for MSVC on Windows; 6 on System V ABI







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 8 at 17:15

























    answered Nov 22 '18 at 15:33









    Govind ParmarGovind Parmar

    13.1k53764




    13.1k53764













    • I have ... ah, thanks, Angew.

      – Peter A. Schneider
      Nov 22 '18 at 15:39











    • Only four arguments are passed in registers in msvc.

      – Biswapriyo
      Nov 23 '18 at 3:07











    • @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

      – Govind Parmar
      Nov 23 '18 at 22:05











    • @GovindParmar you are saying that on x86 in this case second variable is signored.

      – Gox
      Feb 15 at 19:40











    • @Gox If the calling convention is cdecl, then yes.

      – Govind Parmar
      Feb 15 at 19:42



















    • I have ... ah, thanks, Angew.

      – Peter A. Schneider
      Nov 22 '18 at 15:39











    • Only four arguments are passed in registers in msvc.

      – Biswapriyo
      Nov 23 '18 at 3:07











    • @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

      – Govind Parmar
      Nov 23 '18 at 22:05











    • @GovindParmar you are saying that on x86 in this case second variable is signored.

      – Gox
      Feb 15 at 19:40











    • @Gox If the calling convention is cdecl, then yes.

      – Govind Parmar
      Feb 15 at 19:42

















    I have ... ah, thanks, Angew.

    – Peter A. Schneider
    Nov 22 '18 at 15:39





    I have ... ah, thanks, Angew.

    – Peter A. Schneider
    Nov 22 '18 at 15:39













    Only four arguments are passed in registers in msvc.

    – Biswapriyo
    Nov 23 '18 at 3:07





    Only four arguments are passed in registers in msvc.

    – Biswapriyo
    Nov 23 '18 at 3:07













    @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

    – Govind Parmar
    Nov 23 '18 at 22:05





    @Biswapriyo I did mention "the first few" since I wasn't sure of the exact amount. Updated my post with the exact numbers for both PE and SysV ABI

    – Govind Parmar
    Nov 23 '18 at 22:05













    @GovindParmar you are saying that on x86 in this case second variable is signored.

    – Gox
    Feb 15 at 19:40





    @GovindParmar you are saying that on x86 in this case second variable is signored.

    – Gox
    Feb 15 at 19:40













    @Gox If the calling convention is cdecl, then yes.

    – Govind Parmar
    Feb 15 at 19:42





    @Gox If the calling convention is cdecl, then yes.

    – Govind Parmar
    Feb 15 at 19:42













    2














    Normally you'd have this file structure:



    foo.c



    #include "foo.h"

    int bar(int param1)
    {
    return param1*param1;
    }


    foo.h



    int bar(int param1);


    main.c



    #include <stdio.h>
    #include "foo.h"

    int main (void)
    {
    int param = 2, unused = 0;
    printf("%dn", bar(param, unused));
    }


    Now you'll get a compilation error as soon as you use bar with non matching parameters.






    share|improve this answer




























      2














      Normally you'd have this file structure:



      foo.c



      #include "foo.h"

      int bar(int param1)
      {
      return param1*param1;
      }


      foo.h



      int bar(int param1);


      main.c



      #include <stdio.h>
      #include "foo.h"

      int main (void)
      {
      int param = 2, unused = 0;
      printf("%dn", bar(param, unused));
      }


      Now you'll get a compilation error as soon as you use bar with non matching parameters.






      share|improve this answer


























        2












        2








        2







        Normally you'd have this file structure:



        foo.c



        #include "foo.h"

        int bar(int param1)
        {
        return param1*param1;
        }


        foo.h



        int bar(int param1);


        main.c



        #include <stdio.h>
        #include "foo.h"

        int main (void)
        {
        int param = 2, unused = 0;
        printf("%dn", bar(param, unused));
        }


        Now you'll get a compilation error as soon as you use bar with non matching parameters.






        share|improve this answer













        Normally you'd have this file structure:



        foo.c



        #include "foo.h"

        int bar(int param1)
        {
        return param1*param1;
        }


        foo.h



        int bar(int param1);


        main.c



        #include <stdio.h>
        #include "foo.h"

        int main (void)
        {
        int param = 2, unused = 0;
        printf("%dn", bar(param, unused));
        }


        Now you'll get a compilation error as soon as you use bar with non matching parameters.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 '18 at 15:34









        JabberwockyJabberwocky

        28.4k103875




        28.4k103875






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53434075%2ffunction-call-with-more-parameters-than-expected%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to send String Array data to Server using php in android

            Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

            Is anime1.com a legal site for watching anime?