What is the difference between the two code snippets?

In reply to Verif Engg:
event_controls like @ and # in procedural code are not statement by themselves; they are prefixes to the statements that follow. And a statement can be a simple statement, like an assignment, or a block like begin/end or fork/join. And a block is allowed wherever a single statement is allowed.

When you write @(posedge clk); it is really @(posedge clk) null_statement;

I should have given you enough information to answer your question, but here is another variation:

forever 
        @posedge(clk)
        if(vif.sof == 1) begin
           //some code here
        end

Now there is a big difference if a semicolon follows @(posedge clk) or not.